劍指Offer——JZ41.和爲S的連續正數序列【滑動窗口】【√N複雜度數學解法】

題目傳送門


在這裏插入圖片描述


題解

  • 暴力直接gun粗
  • 對於連續區間的問題,前綴和滑動窗口都是不錯的方案。
  • 滑動窗口的解法的時間複雜度很顯然是 O(N)O(N),實際時間複雜的可以常數降低至 O(N2)O(\frac{N}{2})
  • 前綴的話,一遍求前綴數組,然後按照滑動窗口的方式。其實最終都是滑動窗口的思維方式,因爲O(N2)O(N^2) 枚舉起終點的解法太垃圾了

還有一種官方沒有的解法,時間複雜度可以降低至 O(N)O(\sqrt{N})

  • 如果長度爲 nn 的連續整數和爲sumsum,那麼 sumn\frac{sum}{n} 就是中位數。知道中位數和長度,就可以得到整個序列了
  • 可以對 nn 進行分類討論:
    nn是奇數:序列中間數正好是sumn\frac{sum}{n},開始元素爲sumn(n12)\frac{sum}{n}-(\frac{n-1}{2})。條件爲:n % 2 == 1 && sum % n == 0;
    nn是偶數:序列偏左的中間數是sumn\frac{sum}{n},開始元素同上。條件爲:(sum%n) * 2 == n
  • 那麼n的範圍是多少呢?最小肯定是2,最大的時候,我們就需要使整體和最小。那麼久從1開始算起。根據等差數列和公式,得到條件: (1+n)n/2<=S(1+n)*n/2<=Sn<2Sn<\sqrt{2S}
  • 但是注意,偶數的時候,一定會找到符合題意的麼?
  • 例如:n=4的時候,sum=6。按照上述方式劃分得到的是[0,1,2,3]不符合題意。因爲我們只要正整數組合。
  • 或者是否會出現[-1,0,1,2…]這種情況呢?我們需要正確性證明。
  • 注意到我們所取的 nn 的範圍:[2,2S][2, \sqrt{2S}]
  • 在這個範圍內的nn是通過等差數列和公式推導出來的,也就是說,都是滿足等差數列前n項和的n。推算條件的數列最小元素是1.所以,在這個條件下,肯定不會出現非正整數的情況。

AC-Code

  • O(N)O(N)解法
class Solution {
public:
    vector<vector<int> > FindContinuousSequence(int sum) {
        vector<vector<int>> ans;
        int L = 1, R = 1;    // [L. R] 
        int num = 1;
        while(L <= sum / 2) {
            if(num == sum) {
                vector<int> vec;
                for(int i = L; i <= R; ++i) 
                    vec.push_back(i);
                ans.push_back(vec);
                num -= L;
                ++L;
            }
            else if(num < sum) {
                ++R;
                num += R;
            }
            else {
                num -= L;
                ++L;
            }
        }
        return ans;
    }
};
/*     x-n,...,x,...,x+n
      (2*n+1)*x==sum        */
  • O(N)O(\sqrt{N})解法
class Solution {
public:
    vector<vector<int> > FindContinuousSequence(int sum) {
        vector<vector<int>> ans;
        int n = sqrt(sum * 2);
        for(int i = n; i >= 2; --i) {
            if(i & 1 && sum % i == 0 || (sum % i) * 2 == i) {
                vector<int> vec;
                for(int j = 0, k = (sum / i) - (i - 1) / 2; j < i; ++j, ++k)
                    vec.push_back(k);
                ans.push_back(vec);
            }
        }
        return ans;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章