学习目标:
1.对撞指针返回每个数字的平方组成的新数组
2.通过移动窗口返回长度最小的子数组
3.学习螺旋矩阵赋值的思想给矩阵螺旋赋值
1.977有序数组的平方
暴力解法就不细琐了,就是用一个循环将数组内所有的数进行平方,最后再进行排序。这样的算法时间复杂度是O(n+logn)
主要使用的是对撞指针(双指针)的解法:
头指针从头开始,尾指针从数组的末尾开始,设置一个index下标指针用于给新数组赋值,因为有序数组平方之后最大的肯定是数组两边的数字,所以只需要对比两个指针的大小就可以有序将新数组赋值了:
class Solution {
public int[] sortedSquares(int[] nums) {
int l = 0, r= nums.length-1;
int index = nums.length-1;
int res[] = new int[nums.length];
while(l<=r){
if(nums[l]*nums[l] > nums[r]*nums[r]){
res[index--] = nums[l]*nums[l];
l++;
}else{
res[index--] = nums[r]*nums[r];
r--;
}
}
return res;
}
}
2.209长度最小的子数组
暴力解法就不说了,用两个for循环从头到尾遍历一遍,时间复杂度为O(n^2)
这里用的是移动窗口算法,此算法的精髓就是移动窗口的始末位置,结束位置不断向右,当窗口内的值增大到大于目标值后,起始位置就向右到窗口内的值小于目标值,这样不断直到结束位置到数组末尾,中间不断记录窗口的大小长度。
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int l = 0;
int sum = 0;
int res = Integer.MAX_VALUE;
for(int r = 0; r<nums.length;r++){
sum += nums[r];
while(sum >=target){
res = Math.min(res,r-l+1);
sum -= nums[l++];
}
}
return res == Integer.MAX_VALUE ? 0:res;
}
}
3.59螺旋矩阵II
螺旋矩阵思想简单,难度在于代码实现需要步骤多。首先需要找一个循环不变量,那就是每次循环不变的是都是从左到右,右到下,下到左,左到上,所以我们可以从这里入手,假设以左闭右开的思想去做,第一行循环到倒数第二个数,最后一列循环从第一行最后一个数开始,然后每次循环都像这样,这就是宗旨思想。
难度在于如何实现:首先循环次数可以用n/2计算出来(每次循环会减少两行两列),再设置x,y来记录起始位置,i,j为当前循环位置。 第一次for循环:i从x开始,直到第一行倒数第二个数,这时候需要设置一个offSet变量来记录每行赋值到倒数第几个数,初始值为1,因为下一次循环就会到第二行倒数第三个数,不断递增,所以offSet变量每次循环都需要+1。 第二次for循环:跟第一次循环类似,但注意此时赋值时是用arr[i][j],因为此时的j已经在上一次循环抵达了当前循环这一圈的最大值。 第三、四次for循环:此时的i,j都不用初始化,已经在上几次的循环被记录了下来,只需要赋值直到他们回到最小值。 最后:判断n是否时奇数,如果是的话,那么只剩矩阵中间还没赋值,那么直接让arr[x][y]=count就行了,因为此时的x,y已经是最后一个中间数的初始位置了。
class Solution {
public int[][] generateMatrix(int n) {
int [][] arr = new int[n][n];
int x = 0, y= 0;//设置起始位置,遵循左闭右开原则
int loop = n/2;//记录循环次数
int i,j;
int offSet = 1;//一行或一列需要几个不赋值
int count = 1;
while(loop-->0){//循环几圈,如果是奇数后面进行处理
for(j =y;j<n-offSet;j++){//左上到右上
arr[x][j] = count++;
}
for(i =x;i<n-offSet;i++){//右上到右下
arr[i][j] = count++;
}
for(;j>y;j--){//右下到左下
arr[i][j] = count++;
}
for(;i>x;i--){//左下到左上
arr[i][j] = count++;
}
offSet++;
x++;
y++;
}
if(n%2 == 1) arr[x][y] = count;
return arr;
}
}