代码随想录算法训练营Day2
数组专题
- 977.有序数组的平方
- 209.长度最小的子数组
- 59.螺旋矩阵II
977.有序数组的平方
解法一:先平方后快排
时间复杂度:O(nlogn)
空间复杂度:O(1)
说来惭愧,排序算法我写不出来,确实太小白了,我现在就去看。
解法二:先平方然后双指针排序
时间复杂度:O(nlogn)
空间复杂度:O(n)
因为题目里给出了,数组是一个非严格递增的数组排序整数数组,所以可能有负数也有重复。
所以这个数组平方后我们可以想一下会出现,数组两端大然后往中间递减的情况,也就是说大的数都在两端。
根据这种特性,我们可以复制原数组作为输出数组,然后定义首尾指针,选出两指针中的大数将其覆写至输出数组的最后(因为题目要求输出非递减数组),然后大数指针左移或右移,输出数组指针左移。
代码如下:
class Solution {
public int[] sortedSquares(int[] nums) {
int[] result=new int[nums.length];
int left=0,right=nums.length-1,k=result.length-1;
//数组内每个元素都平方
for(int i =0;i<nums.length;i++){
nums[i]=(int)Math.pow(nums[i],2);
}
//因为题目中的这个nums数组比较特殊
//平方之后大的元素都在两端并且是依次向中心递减的
//所以可以使用双指针,比较所指元素大小,然后放到新的数组中。
while(left<=right){
if(nums[left]>nums[right]){
result[k]=nums[left];
k--;
left++;
}else{
result[k]=nums[right];
k--;
right--;
}
}
return result;
}
}
209.长度最小的子数组
解法:滑动窗口
题意要求我们找出最小连续子串,这个子串的和大于等于target。
这个问题的关键在于只用一个for循环怎么挪动i,j指针,挪动哪个指针?我们模拟一边查找子串的过程。
我们通过这个过程发现应该j指针先行,那什么时候挪动i指针?其实我们很容易就想到,要找大于等于target的最小连续子串,所以应该是子串和大于等于target时挪动i指针。
当然我们需要两个变量记录子串长度(len)和子串和(sum),其次我们还需要两个指针,最后初始化len为无穷大。
接下来进入循环,end没跑到数组最后之前都要往前跑,并且没路过一个元素就要把这个元素加入子串和。
重点来啦!我们还要在循环中检查sum是否大于等于target?当满足这个条件时我们应该怎么办?这位同学你说的很棒!我们要将后面那个指针向前移一位对吧?!
但是这里有一个细节需要注意,那就是我们要记录子串长度,选择当前子串长度和以前的长度中最小的那个。这一步操作一定要在后面那个指针前移之前,也就是代码中的start++之前。
那么为什么要在start之前?len记录的是子串的长度,start++之前的end和start这个闭区间是不是就是符合要求的子串?是呀!那我们start++之后再记录len=end-start+1,那么这个东西还是满足我们要求的子串吗?那就有可能不再满足我们的要求了对吧。
然后因为start前移了一位,现在的子串和sum也需要减掉nums[start]。
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int start = 0, end = 0;
int sum = 0;
int len = Integer.MAX_VALUE;
while (end < nums.length) {
sum += nums[end];
while (sum >= target) {
// 这里注意一定是要先更新len,不可以放到start++之后。
len = Math.min(len, end - start + 1);
sum -= nums[start];
start++;
}
end++;
}
return len == Integer.MAX_VALUE ? 0 : len;
}
}
59.螺旋矩阵II
解法:就模拟填数的过程(注意区间边界的不变性)
说实话 这个题我第一眼看到仔细想了想,思路也是去转着圈去填数,也试着写了写,但是需要那些变量还有边界问题怎么去处理都还很模糊,所以就直接看了代码随想录的视频讲解,然后对着代码又看了一遍。
自己又写了一遍然后还是写错了,错的地方就是代码中加注释的地方,我写的matrix[i][j],然后测试用例不通过,我对着测试用例自己手动跑了两遍也没找出错误来,emmmm。
代码如下,定义循环次数,循环次数为n/2是因为如果我们从行数的视角来看每一圈都会带走两行,列同理,如果n为奇数则最后一个元素手动添加就可以。
那么在这里我们需要注意我们对边界的处理,如果每一行或每一列的最后一个数据都要处理的话那就都处理,左开右闭区间;或者最后一个元素都不处理,左闭右开区间。
下面代码我觉得需要注意的细节就是每当一行或者一列执行结束之后,i或者j就自然的增加到了相应的数了,所以不用再处理了,还有要注意的是loop其实在这里也有偏移量的作用,loop控制着最多能填到哪个位置。
class Solution {
public int[][] generateMatrix(int n) {
int loop=0;
int start=0;
int count=1;
int[][] matrix=new int[n][n];
int i,j;
while(loop++<n/2){
for(j=start;j<n-loop;j++){
//这里是start不要填i。
matrix[start][j]=count++;
}
for(i=start;i<n-loop;i++){
matrix[i][j]=count++;
}
for(;j>start;j--){
matrix[i][j]=count++;
}
for(;i>start;i--){
matrix[i][j]=count++;
}
start++;
}
if(n%2==1){
matrix[start][start]=count;
}
return matrix;
}
}