剑指 Offer 57 - II. 和为s的连续正数序列

题目:

思路:

【1】暴力的双指针循环处理的方式:基于题目限制,至少含有两个数,众所周知,x = x/2 + x/2,而在编程中会出现小数被遗弃的情况,所以当x=15时,一半是7,而7+8=15,故应该将边界值调大一些 limit = target/2 + 1; 然后基于数学公式计算多个有序的数的和有 (right + left) * (right - left + 1) / 2; 那么如果当数值小的时候右边界应该右移扩大,而数值过大的时候左边界应该缩小,刚好等于的话便将数值取出。

【2】枚举 + 数学优化:本身也是基于求和公式,推出 y^2+y−x^2+x−2×target=0。

关于 y 的一元二次方程,其中 a=1,b=1,c=−x^2+x−2×target (这里是将不是y的系数都提取出来,当做常量)
如:a*y^2+b*y+c =0
直接套用求根公式即可 O(1) 解得 y ,判断是否整数解需要满足两个条件:
1)判别式 b^2-4ac 开根需要为整数
2)最后的求根公式的分子需要为偶数,因为分母为 2

 

代码展示:

枚举 + 数学优化的方式:

//时间5 ms击败19.39%
//内存39.6 MB击败49.16%
//时间复杂度:O(n) 。
//空间复杂度:O(1) ,除了答案数组只需要常数的空间存放若干变量。
class Solution {
    public int[][] findContinuousSequence(int target) {
        List<int[]> vec = new ArrayList<int[]>();
        int sum = 0, limit = (target) / 2;
        for (int x = 1; x <= limit; ++x) {
            long delta = 1 - 4 * (x - (long) x * x - 2 * target);
            if (delta < 0) {
                continue;
            }
            int delta_sqrt = (int) Math.sqrt(delta + 0.5);
            if ((long) delta_sqrt * delta_sqrt == delta && (delta_sqrt - 1) % 2 == 0) {
                int y = (-1 + delta_sqrt) / 2; // 另一个解(-1-delta_sqrt)/2必然小于0,不用考虑
                if (x < y) {
                    int[] res = new int[y - x + 1];
                    for (int i = x; i <= y; ++i) {
                        res[i - x] = i;
                    }
                    vec.add(res);
                }
            }
        }
        return vec.toArray(new int[vec.size()][]);
    }
}

 

暴力的双指针循环处理的方式:

//时间3 ms击败48.9%
//内存39.4 MB击败76.82%
//时间复杂度:由于两个指针移动均单调不减,且最多移动 target/2+1 次,所以时间复杂度为 O(target),即 O(n) 。
//空间复杂度:O(1) ,除了答案数组只需要常数的空间存放若干变量。
class Solution {
    public int[][] findContinuousSequence(int target) {
        int left = 1, right = 2;
        int limit = target/2 + 1;
        int sum;
        List<int[]> result = new ArrayList<int[]>();
        while (right <= limit){
            sum = (right + left) * (right - left + 1) / 2;
            if (sum == target){
                int count = right - left + 1;
                int[] res = new int[count];
                for (int i = left; i <= right; i++) {
                    res[i - left] = i;
                }
                result.add(res);
                left++;
            }else if (sum < target){
                right++;
            }else {
                left++;
            }
        }
        return result.toArray(new int[result.size()][]);
        //也可以换成下面的方式:
//        int ans[][] = new int[result.size()][];
//        int n=0;
//        for(int[] item : result){
//            ans[n++] = item;
//        }
//        return ans;
    }
}

 

posted @ 2023-02-15 01:58  忧愁的chafry  阅读(12)  评论(0编辑  收藏  举报