977.有序数组的平方
其实我之前有做过这道题,而且老师给的任务中也说明了这道题要用双指针,虽然我记不太清楚了,但凭借着这几个关键点,还是逐渐推出来了。
思路:题目中提到nums数组是递增的,且其中有正、有负,那么一般情况下数组从两端到中间,数值的绝对值应该是逐渐减少的,即使是全为正或者全为负,也是包含在内的。这次将双指针放在数组的两端,逐渐向中间靠拢,再用一个额外的数组来保存各数的平方,请看代码:
class Solution {
public int[] sortedSquares(int[] nums) {
int slow = 0; // 头指针
int fast = nums.length - 1; // 尾指针
int k = nums.length - 1; // 新数组的下标,保证递增的话,从最后一个开始
int[] a = new int[nums.length];
while(slow <= fast){
if(nums[slow] * nums[slow] > nums[fast] * nums[fast]){
a[k--] = nums[slow] * nums[slow]; // 头指针指向的数值大于尾指针指向的数值
slow++;
}else{
a[k--] = nums[fast] * nums[fast]; // 头指针指向的数值小于或等于尾指针指向的数值
fast--;
}
}
return a;
}
}
209.长度最小的子数组
这个题看到的第一眼,再思索了一番,我以为我会的。
原始思路:以为类似于leetcode34在排序数组中查找元素的第一个和最后一个位置,即找到区间的左边界和右边界,然后右减左就是子数组的长度了,是我想的太简单了,这样做的话相当于起点和终点都在动,很难处理,记录一下烂代码:
唉,烂代码连运行都没过,就没提交记录啦。
后来看了一下之前做的代码笔记,慢慢理解了双指针在这个题的特殊之处,滑动窗口即当满足条件时终点不动,起点动,更新完sum、子数组长度和起点后,终点再往后移。上代码:
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int i = 0; // 起点
int result = nums.length;
int sum = 0;
for(int j=0; j< nums.length; j++){ // 终点
sum += nums[j];
while(sum >= target){ // 满足条件
sum -= nums[i];
int subL = j - i + 1; // 当前窗口长度
if(subL < result){
result = subL; // 更新满足条件的子数组长度
}
i++; // 起点更新,滑动窗口
}
}
if(result == nums.length && i == 0){ // 整个数组的和都小于target, 起点i从未更新
return 0;
}
return result;
}
}
59.螺旋矩阵II
思路:区间左闭右开,从上、右、下、左依次赋值,每循环一圈,数组赋值两行,所以循环的次数可设为j<(n/2 + 1),最后需要特殊处理一下n为奇数的情况,即中心赋值。上代码:
class Solution {
public int[][] generateMatrix(int n) {
int[][] a = new int[n][n];
int k = 1;
for(int i=0; i<(n/2 + 1); i++){
// 区间都是左闭右开
// 上面
for(int j=i; j< n-1-i; j++){
a[i][j] = k++;
}
// 右面
for(int j=i; j< n-1-i; j++){
a[j][n-1-i] = k++;
}
// 下面
for(int j=n-1-i; j>i; j--){
a[n-1-i][j] = k++;
}
// 左面
for(int j=n-1-i; j>i; j--){
a[j][i] = k++;
}
}
if(n % 2 == 1) a[n/2][n/2] = k; // 处理一下n为奇数时中心元素
return a;
}
}
总结
在本次数组集训中,更加深刻的认识到了循环不变量以及双指针的灵活使用。