【Java】 劍指offer(57-2) 爲s的連續正數序列

 

本文參考自《劍指offer》一書,代碼採用Java語言。html

更多:《劍指Offer》Java實現合集  java

題目

  輸入一個正數s,打印出全部和爲s的連續正數序列(至少含有兩個數)。例如輸入15,因爲1+2+3+4+5=4+5+6=7+8=15,因此結果打印出3個連續序列1~五、4~6和7~8。post

思路

  指針法:學習

  相似(57-1) 和爲s的兩個數字的方法,用兩個指針small和big分別表明序列的最大值和最小值。令small從1開始,big從2開始。測試

  當從small到big的序列的和小於s時,增長big,使序列包含更多數字;(記得更新序列之和)ui

  當從small到big的序列的和大於s時,增長small,使序列去掉較小的數字;(記得更新序列之和)url

  當從small到big的序列的和等於s時,此時獲得一個知足題目要求的序列,輸出,而後繼續將small增大,日後面找新的序列。指針

  序列最少兩個數字,所以,當small到了s/2時,就能夠結束判斷了。code

  數學分析法:htm

  參考自牛客網丁滿歷險記的答案。

  對於一個長度爲n的連續序列,若是它們的和等於s,有:

  1)當n爲奇數時,s/n剛好是連續序列最中間的數字,即n知足 (n&1)==1 && s%n==0

  2)當n爲偶數時,s/n剛好是連續序列中間兩個數字的平均值,小數部分爲0.5,即n知足 (s%n)*2==n (判斷條件中包含了n爲偶數的判斷)

  獲得知足條件的n後,至關於獲得了序列的中間數字s/n,因此能夠獲得第一個數字爲 (s / n) - (n - 1) / 2,結合長度n能夠獲得全部數字。

  此外,在什麼範圍內找n呢?咱們知道n至少等於2,那至多等於多少?n最大時,序列從1開始,根據等差數列的求和公式根據等差數列的求和公式:S = (1 + n) * n / 2,能夠獲得n應該小於sqrt(2s),因此只須要從n=2到sqrt(2s)來判斷知足條件的n,繼而輸出序列。

 

測試算例 

  1.功能測試(存在/不存在和爲s的序列)

  2.邊界值測試(s=3)

Java代碼

方法一:

//題目:輸入一個正數s,打印出全部和爲s的連續正數序列(至少含有兩個數)。
//例如輸入15,因爲1+2+3+4+5=4+5+6=7+8=15,因此結果打印出3個連續序列1~五、
//4~6和7~8。

public class ContinuousSquenceWithSum {
    //方法一:採用兩個指針的方法
    public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
        ArrayList<ArrayList<Integer> > sequenceList = new ArrayList<ArrayList<Integer> >();
        if(sum<=0)
            return sequenceList;
        
        int small = 1;
        int big = 2;
        int curSum = small+big;
        while(small <= sum/2){
            if(curSum == sum){
                ArrayList<Integer> sequence = new ArrayList<Integer>();
                for(int i=small;i<=big;i++)
                    sequence.add(i);
                sequenceList.add(sequence);
                curSum-=small;
                small++; //這兩行位置前後要注意
            }
            if(curSum < sum){
                big++;
                curSum+=big;
            }
            if(curSum > sum){
                curSum-=small;
                small++;
            }
        }
        return sequenceList;
    }  
}

  

方法二:

    //方法二:數學分析法
    public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
        ArrayList<ArrayList<Integer> > sequenceList = new ArrayList<ArrayList<Integer> >();
        if(sum<=0)
            return sequenceList;
        
        for(int n=(int) Math.sqrt(2*sum);n>=2;n--){
            if(((n&1)==1 && sum%n==0) || ((n&1)==0 && (sum%n)*2==n)){
                ArrayList<Integer> sequence = new ArrayList<>();
                for (int j = 0, k = (sum / n) - (n - 1) / 2; j < n; j++, k++) {
                    sequence.add(k);
                }
                sequenceList.add(sequence);
            }
        }
        return sequenceList;
    }

  

收穫

  1.仍是利用兩個指針,這個技巧要學會

  2.代碼中求連續序列的和,並無每次遍歷計算,而是根據每次操做的狀況而在以前的結果上進行加減,能夠提升效率,值得學習

  3.題目57-1) 和爲s的兩個數字中的指針是從兩端開始,本題指針從1,2開始,注意指針的初始設置。

  4.方法二中,當s/n的餘數爲0.5時,s%n的結果是n/2,而不是1。

  

更多:《劍指Offer》Java實現合集 

相關文章
相關標籤/搜索