997.有序数组的平方
解题方法:双指针,一个for循环
分析题意:
- 题目给定数组是一个有序的数组
- 要返回每个数的平方,那么新数组中的最大值一定是在数组的两端
解题步骤:
-
定义左右两个指针(
i,j)分别指向数组的前后两端 -
定义一个指针(
k)指向新数组的末尾 -
开始遍历,结束条件为
i <= j(这里的 = 需要思考,如果没有 = 的话就会把 i = j 的那个数漏掉)-
如果 下标为
i的值的平方 > 下标为j的值的平方- 将 下标为
i的值的平方赋给下标为K的值 i向后移动一位,k向前移动一位
- 将 下标为
-
如果 下标为
i的值的平方 <= 下标为j的值的平方(这里也需要思考 = 的情况,相等时说明 i , j 指向的值的平方相等,所以可以直接归到这一种情况中)- 将 下标为
j的值的平方赋给下标为K的值 j向前移动一位,k向前移动一位
- 将 下标为
-
图示(图片来源:代码随想录)
解题代码:
class Solution {
public int[] sortedSquares(int[] nums) {
//定义新数组,长度等于原数组
int[] result = new int[nums.length];
//定义指针指向新数组的末尾
int k = result.length - 1;
for(int i = 0,j = nums.length - 1;i <= j;){
if(nums[i] * nums[i] > nums[j] * nums[j]){
result[k] = nums[i] * nums[i];
i++;
k--;
}else{
result[k] = nums[j] * nums[j];
j--;
k--;
}
}
return result;
}
}
209长度最小的子数组(滑动窗口)
解题思路
双指针,一个for循环
图片来源:代码随想录
需要理解的点
**窗口:**满足其和 ≥ s 的长度最小的 连续 子数组
**窗口起始位置移动:**当前窗口的值大于s,窗口就要向前移动(缩小窗口)
**窗口结束位置移动:**窗口的结束位置就是遍历数组的指针,也就是for循环里的索引
对应步骤:
-
for循环中变量是表示 的 滑动窗口的终止位置
-
计算当前窗口中元素值总和(sum)
-
while循环判断当前窗口元素值的总和是否大于swhile(sum>=s) -
获取当前窗口的长度(
subLength= 终止位置 - 初始位置 + 1) -
将最终需要返回的结果
result和subLength比较取更小的一个赋值给resultresult初始默认值为:Integer.MAX_VALUE -
窗口起始位置移动,计算新窗口的元素值总和 (容易忽略)
-
窗口起始位置+1
实现代码
class Solution {
public int minSubArrayLen(int target, int[] nums) {
if(nums==null || nums.length==0){
return 0;
}
int i = 0; //初始位置
int totalNum = 0;
int result = Integer.MAX_VALUE;
for(int j = 0;j < nums.length;j++){
totalNum += nums[j];
while(totalNum >= target){
int subLength = j - i + 1; //计算当前窗口的长度
result = Math.min(result,subLength);//比较当前数组长度和最大值,返回给result
totalNum -= nums[i];//初始位置移动后需要更新数组和
i++;//初始位置向前移动
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
}s
两个注意
1.为什么用 while 不用 if ( 很重要!!!)
因为窗口是需要不断移动的,并不是只判断一次就完事了
2.为什么时间复杂度是O(n)
不能以为for里放一个while就以为是O(n^2), 主要看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。
59.螺旋矩阵Ⅱ
解题思路:
图片来源:代码随想录
求解本题要坚持循环不变量原则,同时通过横纵坐标定位。
模拟顺时针画矩阵的过程:
- 填充上侧从左到右
- 填充右测从上到下
- 填充下侧从右到左
- 填充左侧从下到上
由外向内一圈一圈这么画下去。
要画四条边,每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,一圈按照统一的规则画下来。
解题时的想法:
-
应该循环多少次才能把矩阵赋值完成呢?如果 n = 4 ,那么则需要 n/2 = 2 遍才能赋值完成,如果 n 是奇数的话还需要另外考虑最中间的赋值
-
对每条边的处理应该使用相同的规则(左闭右开),以及如何确定遍历的最终结束条件(也就是遍历到哪里 利用偏移量offset计算)
-
遍历完一圈后,下一次遍历的起始位置以及偏移量都会发生变化
解题代码:
class Solution {
public int[][] generateMatrix(int n) {
int[][] nums = new int[n][n];
int loop = 0; //循环的次数
int start = 0; //循环开始的点
int offset = 1;//偏移量
int count = 1; //定义填充的数字
int i,j;
while(loop++ < n/2){
//上侧从左到右
for(j = start;j < n - offset;j++){
nums[start][j] = count++;
}
//右侧从上到下
for(i = start;i < n - offset;i++){
nums[i][j] = count++;
}
//下侧从右到左
for(;j > start;j--){
nums[i][j] = count++;
}
//左侧从下到上
for(;i > start;i--){
nums[i][j] = count++;
}
start++;
offset++;
}
if(n % 2 == 1){
nums[start][start] = count;
}
return nums;
}
}
个人小结: 感觉数组的题目不是特别难,主要需要理解几个重要的思想,一个是二分法和螺旋矩阵中的循环不变量,确定区间;另一个就是利用双指针思想解决移除元素和滑动窗口,刷完后感觉研究出这些算法的佬太牛了,自己还需要努力,脚踏实地的一步步往前走。