代码随想录算法训练营第2天 | 题目977 209 59
209:题目链接:[209]
文章讲解:[209代码随想录]
视频讲解:https://www.bilibili.com/video/BV1tZ4y1q7XE
题目名称:977.有序数组的平方
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
示例 1:
输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100],排序后,数组变为 [0,1,9,16,100]
示例 2:
输入:nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]
第一想法:
可以使用暴力排序,但由于题目所给非递减顺序数组,自然联想双指针法,但此时存在负数,平方后顺序数组需要分为负数部分以及正数部分。
解答思路:
双指针法
数组其实是有序的, 只不过负数平方之后可能成为最大数了。
那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。
此时可以考虑双指针法了,i指向起始位置,j指向终止位置。
定义一个新数组result,和A数组一样的大小,让k指向result数组终止位置。
如果A[i] * A[i] < A[j] * A[j] 那么result[k–] = A[j] * A[j]; 。
如果A[i] * A[i] >= A[j] * A[j] 那么result[k–] = A[i] * A[i]; 。
困难:无
收获:
考虑局部的双指针法,重新创造一个空数组来存放结果而不是直接在数组上排序是一个行之有效的思路。
题目名称:209.长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
示例:
输入:s = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
提示:
1 <= target <= 10^9
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^5
第一想法:
使用快慢指针做,每次遍历慢指针,移动快指针找到最小数组。但在使用时遇到错误,对快指针的移动总是出现问题
public int minSubArrayLen(int target, int[] nums) {
int fast = 0, slow = 0,sum=0;
int minlen = nums.length;
for (slow = 0; slow < nums.length;slow++) {
sum=0;
fast=slow;
while(sum<target&&fast<nums.length){
sum=sum+nums[fast];
if(sum>=target&&fast-slow==0){break;}
if(slow==0&&sum<target&&fast== nums.length-1) return 0;
fast++;
}
if(minlen>((fast-slow)+1)){minlen=((fast-slow)+1);}
}
return minlen;
}
测试用例:11
[1,2,3,4,5]
测试结果:2
期望结果:3
出现失败
解答思路:
此处使用滑动窗口,移动的是滑动窗口的右端指针,在满足数组条件后获得结果,并收缩左端指针使得不满足条件。
在本题中实现滑动窗口,主要确定如下三点:
-窗口内是什么?
-如何移动窗口的起始位置?
-如何移动窗口的结束位置?
窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。
窗口的起始位置如何移动:如果当前窗口的值大于等于s了,窗口就要向前移动了(也就是该缩小了)。
窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。
困难:
自己的解答中对指针的变化情况不了解,方法很像暴力解法,没有理解滑动窗口是首末位置来回变换的过程
收获:
滑动窗口是双指针法的变形,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。
题目名称:59.螺旋矩阵II
给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
示例:
输入: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]
第一想法:
通过螺旋来录入数值,但尝试中出现错误
解答思路:
把螺旋的过程解析为不同的圈数,设置loop为循环圈数,为n/2,这里一圈下来,我们要画每四条边,这四条边怎么画,每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来。在每一圈都更新开始位置的(i,j)。注意,当n为奇数时,单独考虑中心值。
困难:
记得考虑奇数情况下的中心值,loop=n/2,时循环不会覆盖最后的中心值
收获:
在数组中要考虑处理时的边界开闭的情况,在统一的循环中,确定边界开闭十分重要。
数组的总结
1.二分法
二分法的核心思想是循环不变量原则,只有在循环中坚持对区间的定义,才能清楚的把握循环中的各种细节。需要注意左闭右闭合左闭右开的区分。
2.双指针法
即快慢指针,使用一个循环实现两个循环的任务,数组是连续的空间,只能覆盖不能删除,在进行删除数组中某个元素的任务时,快指针进行遍历,不出现对应值时,慢指针值等于快指针值,当出现对应值时,慢指针在这次遍历中不会跟随快指针,即不执行相等,造成延后一位,是得后面的元素覆盖要删除的元素直到最后一位。
3.滑动窗口
滑动窗口是特殊的双指针法,可以通过变化滑动窗口的首尾实现。滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。
4.模拟任务
进行二维数组的模拟任务时需要明确循环不变量的原则,同时要确定边界,保证代码的原则性。