目录
977.有序数组的平方
题目链接:力扣
文章讲解:代码随想录
视频讲解: 双指针法经典题目 | LeetCode:977.有序数组的平方_哔哩哔哩_bilibili
解题思路:
有序数组的平方使用双指针,先明确一点由于只能在两端取到最大值,所以一个指针指向起始位置,一个指针指向终止位置,因此只需要不断的比较左右这两个指针指向元素平方的数值大小,再把最大的值从后往前逆序放依次在新的数组里面即可,但注意这两个指针并不是同时进行移动的,只有满足左边指针指向的元素的平方大于右边指针指向元素的平方,左边指针才能右移一位,反之则右边指针左移一位,都需要在各自的if条件语句中进行判断决定!for循环终止的条件一定是左边指针的下标索引值小于等于右边指针的下标索引值,如果仅小于,则如果在下标为2的位置相遇,2<2为假,就停止循环了,那么下标为2处的元素是没机会添加到新的数组中的。
class Solution {
public int[] sortedSquares(int[] nums) {
int index = nums.length - 1;
int[] result = new int[nums.length];
for(int i = 0, j = nums.length - 1; i <= j; ){
if(nums[i] * nums[i] > nums[j] * nums[j]){
result[index--] = nums[i] * nums[i];
i++;
}else{
result[index--] = nums[j] * nums[j];
j--;
}
}
return result;
}
}
209.长度最小的子数组
解题思路:
使用滑动窗口寻找长度最小的子数组使用的还是双指针的方法,但是最关键的是在一层for循环中指针j其实是指向终止位置的指针,而动态的寻找指向起始位置的指针i是理解滑动窗口的精髓!可以先这么理解[1,1,3,7],其target目标值是6,分两步去分析:
第一步:使用的一层for循环的作用是利用指向终止位置的指针j先从索引位置为0开始累加,直到找到连续元素的和大于等于target目标值是6的子数组;只有在第一步找到子数组,才能执行第二步。
第二步:然后在找到满足的子数组中,保持指向终止位置的指针j位置不动,移动指向起始位置的指针i,当然指针i也是从0开始,不断的向右移动,直到其不断缩小长度的数组内的元素和不再大于等于target目标值为6,就不再移动指针i了,此时所得到的数组长度就是长度最小的子数组了。
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int sum = 0;
int subL;
int result = Integer.MAX_VALUE;
for(int i = 0, j = 0; j < nums.length; j++){
sum += nums[j];
while(sum >= target){
subL = j - i + 1; //第一次执行while循环是计算第一步中找到满足条件的子数组的长度,之后都是重新计算满足条件的子数组的长度
result = Math.min(result, subL); //这里是为了在循环内不断更新满足条件的子数组长度,如果没进入到第二步,说明在第一步没有找到满足条件的子数组,那么result值没有更新,还是初始的定义值,就是使用三元运算符中的条件及其返回值
sum -= nums[i++]; //指向起始位置的指针往右移动的时候其子数组内的元素的和也要减去当前指针i指向的元素值,才能右移一次,然后再对循环体执行的条件进行判断
}
}
return result == Integer.MAX_VALUE ? 0:result ; //三元运算符(可以理解为 == ? : 这三个元组成的条件表达式,突然想到就这么说一嘴哈哈哈,这不是重点!!!)
}
}
59.螺旋矩阵II
题目链接:力扣
文章讲解:代码随想录
视频讲解:一入循环深似海 | LeetCode:59.螺旋矩阵II_哔哩哔哩_bilibili
解题思路:
1、首先得确定需要进行几次循环一圈进行赋值,直接记住n/2就可以了,也可以代入数字验证也能发现规律,如果n是奇数,则在循环赋值结束后直接将中间值进行赋值即可,这里的中心就是mid = n/2, 就是(mid, mid),可以代入数字验证一下也能发现规律。
2、在进行每一圈顺时针赋值的时候一定是从第一条边保持横坐标不变开始迭代的,因为这和多维数组的索引方式有关,如下图所示
若按照顺时针赋值操作,根据图中每个坐标的变化规律,可以得到第一条边赋值时一定先保持横坐标不变,第二条赋值时纵坐标不变,第三条赋值时横坐标不变,第四条边赋值时纵坐标不变,至此按照这样的思考逻辑就可以编写出下面的代码啦!
class Solution {
public int[][] generateMatrix(int n) {
int[][] nums = new int[n][n];
int circle = 0;
int count = 1;
int mid = n/2; //如果n是奇数,则最中间位置就是(mid, mid)
//循环边有关的变量
int starti = 0;
int startj = 0;
int offset = 1; //每条边的处理按照左闭右开的原则,每次循环一圈后开始下一圈的矩阵中元素赋值,每条边所能赋值的个数也在不断的减1
while(circle < n/2){
int i = starti;
int j = startj;
//第一条边赋值,先保持横坐标不变,纵坐标不断变化,使用左闭右开的原则的话,还需要减去一个偏移量offset,比如输入n = 4,那么第一条边赋值只能是0,1,2,因此代入数字可以验证得到结论 j < n - offset,而且每次循环一圈之后开始下一轮赋值offset也会加1
for(; j < n - offset; j++){
nums[i][j] = count++;
}
//第二条边赋值,
for(; i < n - offset; i++){
nums[i][j] = count++;
}
//第三条边赋值
for(; j > startj; j-- ){ //这里就是while循环内为什么重新赋值给i,j,因为如果不赋值,starti和startj会不断变化,但需要与原来的值进行判断
nums[i][j] = count++;
}
//第四条边赋值
for(; i > starti; i--){
nums[i][j] = count++;
}
starti++; //循环一圈赋值后更新下一轮循环一圈赋值的起点横坐标
startj++; //循环一圈赋值后更新下一轮循环一圈赋值的起点纵坐标
offset++; //循环一圈赋值后更新下一轮循环一圈赋值的偏移量,从而满足给每条边赋值时的左闭右开原则
circle++; //循环一圈赋值后更新圈数,判断是否达到while循环体的终止条件,从而判断是否需要进行循环一圈赋值操作
}
//如果n是奇数,则还剩最后一个中间值,直接进行赋值即可
if( n % 2 == 1){
nums[mid][mid] = count;
}
return nums;
}
}