1.4 977.有序数组的平方
注意题目说这个数组是整数数组,里面可能是有负数的,题目也没有对空间复杂度的要求
最直白的想法:把所有元素平方之后再进行排序(快排),但是这种方式的时间复杂度是O(nlogn)
O(n)的解题方法:双指针法
这个题对空间复杂度没有要求,所以可以定义一个新的数组用来存储结果数组
那这个题是怎么想到用双指针法来做的呢?就是这个数组的特性,他在平方之后的大小变化趋势是两端的数值是最大的,都向中间递减
注意:这里循环条件是pre≤after(其实也是因为区间是左闭右闭得),因为如果不加等于,那就是在这俩指针相等的时候这个循环直接退出了,那就是会把这个元素给落下,但是这个元素也得放在最后的result数组中啊,所以就得小于等于
易错点:
-
left和right、以及index都要动(容易忘记移动)
1.5 209.长度最小的子数组
暴力法:两层for循环,遍历出所有子序列的情况
class Solution { public int minSubArrayLen(int target, int[] nums) { //暴力法 int min=nums.length; int len=0; boolean exist=false; //外层循环控制初始位置 for(int i=0;i<nums.length;i++){ int sum=0; //内层循环控制终止位置 for(int j=i;j<nums.length;j++){ sum+=nums[j]; if(sum>=target){ exist=true; len=j-i+1; break; } } if(min>len){ min=len; } } if(!exist){ return 0; } return min; } }
滑动窗口法:和之前的双指针思路类似,也是由两个指针进行操作,只不过我们是取两个指针中间的集合
其实是用一个for循环来做两个for循环所做的事情
但是用下面的思路即使是让for循环滑动窗口的终止位置,力扣还是会显示超出时间限制
class Solution { public int minSubArrayLen(int target, int[] nums) { //滑动窗口法(和双指针类似) //当窗口中的和大于target时,left移动; //当窗口中的和小于target时,right移动; //记录大于等于target的长度 int left=0; int sum=0; int min=nums.length; int len=0; boolean isExist=false; for(int right=0;right<nums.length;right++){ sum=0; for(int i=left;i<=right;i++){ sum+=nums[i]; } if(sum>=target){ len=right-left+1; left++; right--; isExist=true; if(len<min){ min=len; } } } if(isExist) return min; else return 0; } }
改进之后:求窗口内数字元素的和不要用内层循环求,而是直接求,然后滑动窗口的时候,在原来和的基础上+或-就行
class Solution { public int minSubArrayLen(int target, int[] nums) { //滑动窗口法(和双指针类似) //当窗口中的和大于target时,left移动; //当窗口中的和小于target时,right移动; //记录大于等于target的长度 int left=0; int sum=0; int min=nums.length; int len=0; boolean isExist=false; for(int right=0;right<nums.length;right++){ sum+=nums[right]; if(sum>=target){ isExist=true; //right不动,left动;并记录长度 len=right-left+1; if(len<min){ min=len; } sum-=nums[left]; left++; sum-=nums[right]; right--; } } if(isExist) return min; else return 0; } }
以上思路的要点/易错点:
-
求窗口内数字的和不要用循环,在外层循环求,当窗口滑动时,在原来和的基础上加或减就行
-
当判断和大于等于target,窗口要开始移动时,集左指针要向右移动,右指针不能动,但因为外循环右指针必然会++,所以这里right还要--,并且在sum中也减去nums[right]的值
主要步骤:
-
定义滑动窗口的边界
-
求窗口内数字元素的和
-
判断和是否≥target
-
大于/等于:滑动窗口
-
小于:正常移动右指针,再求和,再判断
-
1.6 59.螺旋矩阵Ⅱ
class Solution { public int[][] generateMatrix(int n) { int[][] result=new int[n][n]; //先得到共有多少层(-1) int levelNum=n/2; int num=1; for(int i=0;i<levelNum;i++){ for(int j=i;j<(n-1-i);j++){ result[i][j]=num; num++; } for(int j=i;j<(n-1-i);j++){ result[j][n-1-i]=num; num++; } for(int j=(n-i-1);j>i;j--){ result[n-i-1][j]=num; num++; } for(int j=(n-i-1);j>i;j--){ result[j][i]=num; num++; } } if(n%2!=0){ result[n/2][n/2]=num; } return result; } }
注意:错误的地方在于当n是奇数时,最后一圈只剩了一个元素
class Solution { public int[][] generateMatrix(int n) { int levelNum=n/2+1; int[][] result=new int[n][n]; int num=1; //注意:这里循环条件是小于,因为如果有等于,当n是偶数时,就会多循环一圈 //但是小于的话,当n等于奇数时又会少循环一圈,所以要在后面补n为奇数时,最后剩下的一个数 for(int i=1;i<levelNum;i++){//i是层数 //上:行:层数-1;列:[层数-1;n-层数-1] for(int j=(i-1);j<=(n-i-1);j++){ result[i-1][j]=num; num++; } //右:行:[层数-1,n-层数-1];列:n-层数 for(int j=(i-1);j<=(n-i-1);j++){ result[j][n-i]=num; num++; } //下:行:n-层数;列:[n-层数,层数+1-1] for(int j=(n-i);j>=i;j--){ result[n-i][j]=num; num++; } //左:行:[n-层数,层数+1-1];列:层数-1 for(int j=(n-i);j>=i;j--){ result[j][i-1]=num; num++; } } if(n%2!=0){ result[n/2][n/2]=num; } return result; } }
注意:
-
变化的行数和列数之间有连续的关系
易错点:
-
填充的数是1-n^2,而不是每个都要平方
-
注意所在层数和数组下标的关系(下标是从0开始的)