剑指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;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章