700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 剑指 Offer 57 - II. 和为s的连续正数序列 思考分析

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

时间:2020-09-05 23:54:41

相关推荐

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

输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。

序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。

示例 1:

输入:target = 9

输出:[[2,3,4],[4,5]]

示例 2:

输入:target = 15

输出:[[1,2,3,4,5],[4,5,6],[7,8]]

限制:

1 <= target <= 10^5

暴力解,通过

注意,子序列长度大于等于二,所以我们循环以二分之一个目标作为结束标志,当然也要注意一下要不要+1,以及循环结束条件是小于等于还是等于的问题。

AC代码:

class Solution {public:vector<vector<int>> findContinuousSequence(int target) {int start = 1;vector<vector<int>>result;vector<int>smallresult;int half_target = (target*0.5) + 1;while (start <= half_target){int sum = 0;int flag = 0;smallresult.clear();for (int i = start;i <= half_target;i++){flag = 1;sum += i;smallresult.push_back(i);if (sum > target){break;}else if (sum == target){result.push_back(smallresult);break;}}if (flag == 1) start++;}return result;}};

优化暴力解

优化之后的代码:仍然是暴力法,不过将push_back换成了emplace_back,然后将插入和清除操作放入了sum == target的逻辑块中,减少了插入以及删除元素带来的时间损失。

class Solution {public:vector<vector<int>> findContinuousSequence(int target) {int start = 1;vector<vector<int>>result;vector<int>smallresult;int half_target = (target*0.5) + 1;while (start <= half_target){int sum = 0;int flag = 0;for (int i = start;i <= half_target;i++){flag = 1;sum += i;if (sum > target){break;}else if (sum == target){smallresult.clear();for(int j=start;j<=i;j++) smallresult.emplace_back(j);result.emplace_back(smallresult);break;}}if (flag == 1) start++;}return result;}};

再次优化思路

一开始我列下了两个优化思路:

1、若只有一组结果,或者没有结果,能不能找到一种方法直接返回结果

2、如果已经完成一组结果,下一组的推断能不能用到上一组的信息。

接下来就是一大堆乱改步长的操作,也就是说,之前每完成一次子序列和没有完成子序列,下一次的起始点都是原起始点+1,此时我们不这样做,而是在完成一次子序列后,修改下一次的起始点。

修改思路:

此处的i是指完成一次子序列时的子序列的右边界

1、new_start=(i+start)0.5+1; (经过验证,是错误的)

2、new_start= i0.5+1; (经过验证,是错误的)

3、new_start=start+2; 这个倒是可以。。。不过优化不是很多

双指针(滑动窗口)

我们用两个指针 L 和 R 表示当前枚举到的以 L 为起点到 R 的区间,sum 表示[L,R]的区间和,由求和公式可知;

也就是说,如果确定了一对L、R,就可以直接得到sum值,而不需要累加计算了(省时序)

如果sum<target 则说明指针R还可以向右拓展使得sum 增大,此时指针R向右移动,即 r+=1

如果sum>target 则说明以L为起点不存在一个R使得 sum=target,此时要枚举下一个起点,指针L向右移动,即l+=1

如果sum==target 则说明我们找到了以L为起点得合法解 [l,r],我们需要将 [l,r][l,r] 的序列放进答案数组,且我们知道以L为起点的合法解最多只有一个,所以需要枚举下一个起点,指针L向右移动,即 l+=1

(题外话,官方解的第三种方法讲解有问题。。。)

而且感觉这个方法也没有用到区间信息,只是高级在使用了公式。

class Solution {public:vector<vector<int>> findContinuousSequence(int target) {vector<vector<int>>vec;vector<int> res;for (int l = 1, r = 2; l < r;){int sum = (l + r) * (r - l + 1) / 2;if (sum == target){res.clear();for (int i = l; i <= r; ++i) res.emplace_back(i);vec.emplace_back(res);l++;}else if (sum < target) r++;else l++;}return vec;}};

另外还发现了一个C++语法的问题:

c++11 之emplace_back 与 push_back的区别

总结就是能用emplace_back就用emplace_back。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。