目录
题目概述(简单难度)
思路与代码
思路展现(滑动窗口)
代码示例
代码解析:
总结
题目概述(简单难度)
输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
示例 1:
输入:target = 9 输出:[[2,3,4],[4,5]]
示例 2:
输入:target = 15 输出:[[1,2,3,4,5],[4,5,6],[7,8]]
题目链接:
点我进入leetcode
思路与代码
思路展现(滑动窗口)
这道题目是数组中非常经典的滑动窗口的题目, 题解看个就行:
点我进入题解
但是有几个需要注意的点
1:首先注意我们的滑动区间是一个左闭右开的区间
2:后期不管是我们的区间是大还是小,我们的窗口的左边界和右边界永远只能向右移动
代码示例
class Solution { public int[][] findContinuousSequence(int target) { // 滑动窗口的左边界 int i = 1; // 滑动窗口的右边界 int j = 1; //滑动窗口内的值的总和 int sum = 0; /* i如果大于target/2的话,就不存在连续正整数序列了 */ //定义一个list用于存储我们连续正整数数列,存储的类型为int[] List<int[]> list = new ArrayList<>(); while(i <= target / 2) { if(sum < target) { // 右边界向右移动 sum += j; //注意j++才能保证是一个左闭右开区间 j++; }else if(sum > target) { // 左边界向右移动 sum -= i; i++; }else { //因为是左闭右开区间,所以次数应该是j-i,而不是j-i+1,大家可以仔细体会 //创建一个数组,把我们每次符合条件的数组进行存储 int[] arr = new int[j-i]; for(int k = i ; k < j ; k++) { //注意要把符合条件的数字存入我们的arr数组,这里的设计比较巧妙,大家好好体会 arr[k-i] = k; } //存储完毕后放入到我们的list集合 list.add(arr); //此时我们找到一组后,开始找下一组,是让i++,并且从总数sum中减掉我们的i sum -= i; i++; } } //循环完毕后我们list中所存储的就是我们所有符合条件的连续正整数序列,然后使用toArray方法将其转换为二维数组 return list.toArray(new int[0][]); } }
代码解析:
这段代码还是有很多设计的比较精妙的地方的,我们来解析一下代码:
1:
while(i <= target / 2)
滑动窗口的循环条件改成i <= target/2更好,因为要求是连续正整数,第一个数大于target的一半就不可能了
2:
int[] arr = new int[j-i]
因为是左闭右开区间,所以次数应该是j-i,而不是j-i+1,大家可以仔细体会
3:
arr[k-i] = k;
注意要把符合条件的数字存入我们的arr数组,这里的设计比较巧妙,大家好好体会
4:
sum -= i; i++;
这两步是必不可少的,原因是当我们找到了连续的正整数序列后,此时需要继续往下找,我们的方法是让我们的i往后走,从i+1开始,然后再继续判断,同时我们的总数sum需要减掉我们的i.
5:
return list.toArray(new int[0][]);
这一步就是把我们的list集合转变为数组进行返回,大家可以通过这篇博客来复习一下集合转数组.
点我进入掘金
可以看到我们这里我们为什么是0,不是res.size()或者其他的,原因就是数组空间等于0时,将会动态的创建和集合size相同空间大小的数组,性能是最好的。
总结
考察对于数组滑动窗口的掌握