第一章 数组part02
977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II ,总结
如果基础不好的录友,建议直接视频讲解,这样避免很多时间浪费,因为没接触过的算法,不是轻易就能靠自己思考想出来的。
拓展题目可以先不做
详细布置
**977.有序数组的平方 **
题目建议: 本题关键在于理解双指针思想
题目链接:https://leetcode.cn/problems/squares-of-a-sorted-array/
文章讲解:https://programmercarl.com/0977.%E6%9C%89%E5%BA%8F%E6%95%B0%E7%BB%84%E7%9A%84%E5%B9%B3%E6%96%B9.html
视频讲解: https://www.bilibili.com/video/BV1QB4y1D7ep
209.长度最小的子数组
题目建议: 本题关键在于理解滑动窗口,这个滑动窗口看文字讲解 还挺难理解的,建议大家先看视频讲解。 拓展题目可以先不做。
题目链接:https://leetcode.cn/problems/minimum-size-subarray-sum/
文章讲解:https://programmercarl.com/0209.%E9%95%BF%E5%BA%A6%E6%9C%80%E5%B0%8F%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84.html
视频讲解:https://www.bilibili.com/video/BV1tZ4y1q7XE
59.螺旋矩阵II
题目建议: 本题关键还是在转圈的逻辑,在二分搜索中提到的区间定义,在这里又用上了。
题目链接:https://leetcode.cn/problems/spiral-matrix-ii/
文章讲解:https://programmercarl.com/0059.%E8%9E%BA%E6%97%8B%E7%9F%A9%E9%98%B5II.html
视频讲解:https://www.bilibili.com/video/BV1SL4y1N7mV/
**总结 **
题目建议:希望大家 也做一个自己 对数组专题的总结
文章链接:https://programmercarl.com/%E6%95%B0%E7%BB%84%E6%80%BB%E7%BB%93%E7%AF%87.html
977.有序数组的平方
题目链接
解题思路
首先这题要根据题的说明,是一个非递减数组,负数平方是正有可能超过正数的平方,那么在这个数组最大最小值一定出现在头部或尾部 ,在这个数组的任意一个子数组都是如此。 头尾双指针解决。
这题只能以空间换时间,不断缩数组,取头尾的最大值赋值给新数组的 尾部->0的位置。
总结踩坑:刚开始一直想在本数组操作,想空间复杂度O(1),那么一定会破环这个非递减数组的特性,导致无法解出本题。 所以这里不要破坏原数组,要把结果收集到新数组上。
code
public int[] sortedSquares(int[] nums) {
//因为是有序数组,这个想到平方后的最大数一定在俩边
//每次把最大的选出来,左指针+1 或 右指针-1
//要定义个新的result数组存储结果集
int left=0;
int right=nums.length-1;
int[] result=new int[nums.length];
int index=nums.length-1;
while(left<=right){
if(Math.abs(nums[left])>Math.abs(nums[right])){
result[index--]=nums[left]*nums[left];
left++;
}else{
result[index--]=nums[right] * nums[right];
right--;
}
}
return result;
}
209.长度最小的子数组
题目链接
解题思路
O(n) 复杂度 一个for循环解决问题,题目说最小子数组,可以联想到滑动窗口问题
1.找到满足的窗口,继续找下一个窗口,看那个窗口最满足题目要求
2.循环的索引需要考虑,这个索引是窗口的起始位置还是终止位置呢?
假设起始位置,开始从头遍历,找到了一个符合的窗口,此时索引来到这个符合窗口的终止位置,索引循环的索引一定是窗口的终止位置。
3.确定了窗口的终止位置,那么要考虑窗口的起始位置,初始的窗口起始位置一定是0,此时找到了一个符合的窗口,那么就要开始找下一个窗口,这时窗口的起始位置就要变动了,窗口向前移动,直到遇到某个窗口不符合结果,那么窗口的终止位置就要开始变动了直到在遇到符合的窗口,周而复始直到循环结束。
4.时间复杂度分析
终止窗口扫描每一个元素O(n) 起始窗口扫描每一个元素O(n) , O(2n) 所以时间复杂度是O(n)
code
public int minSubArrayLen(int target,int[] nums){
if(nums==null || nums.length==0){
return 0;
}
//收集结果,如果值没有变化返回0即没有收集到结果
int length=Integer.MAX_VALUE;
//窗口起始位置
int left=0;
//这个窗口的值
int sum=0;
for(int right=0;right<nums.length;right++){
//窗口变化记录sum
sum+=nums[right];
//找到符合的右窗口位置
while(sum>=target){
//收集右窗口第一次满足的结果
length=Math.min(length,right-left+1);
//窗口左边开始变化,直到遇到不满足的左窗口
sum-=nums[left];
left++;
}
}
return length==Integer.MAX_VALUE?0:length;
}
总结:所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果,
** 考虑好循环的索引是窗口的终止位置,然后在控制窗口的起始位置是解题的关键**
59.螺旋矩阵II
题目链接
解题思路
控制好边界,维持左闭右开,每条边处理相同数量的空格,不要越界,这样才好写代码不容易乱
考虑遍历几次,奇数少循环一圈,矩阵中间的位置要单独处理
写的时候代入例子自然就通过了。
code
//保持边界条件左闭右开 循环不变量
public int[][] generateMatrix(int n) {
//定义二维数组收集结果
int[][] res=new int[n][n];
//定义数组的起始位置
int x=0,y=0;
//定义循环几圈,n为奇数 必定少循环一圈,矩阵中间的位置要单独处理
int loop=n/2;
int count = 1; // 用来给矩阵赋值 他控制1-n*n的数赋值给二维数组
int offset = 1; // 需要控制每一条边遍历的长度,每次循环右边界收缩一位
int i,j;
while (loop-->0){
i=x;
j=y;
//第一条边 保持左闭右开 i=0 j=0
for (;j<n-offset;j++){
res[i][j]=count++;
}
//第二条边 i=0 j=2
for(;i<n-offset;i++){
res[i][j]=count++;
}
//第三条边 i=2,j=2
for(;j>=offset;j--){
res[i][j]=count++;
}
//第4条边 i=2 j=0;
for(;i>=offset;i--){
res[i][j]=count++;
}
//第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
x++;
y++;
// offset 控制每一圈里每一条边遍历的长度
offset++;
}
if(n%2==1){
int mid=n/2;
res[mid][mid]=count;
}
return res;
}