leetcode 977.有序数组的平方 、 209.长度最小的子数组 、59.螺旋矩阵II 。
leecode 977 有序数组的平方
题目链接 :https://leetcode.cn/problems/squares-of-a-sorted-array/description/
题目
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
示例 1:
输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]
示例 2:
输入:nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]
解题思路
这道题可以用两层for循环暴力解决,但是暴力的时间复杂度为O(n*n),时间复杂度太高。我们要想办法降低时间复杂度,最好是遍历一遍数组就可以解决了。那一般来说,能够想到的是双指针,可是双指针如一前一后,快慢这类的似乎想不到合理的能够解决这道题。此时回到题目本身,我们返回的是每个数字平方组成的新数组,如 [-4,-1,0,3,10],返回 [16,1,0,9,100]。分析示例,我们找到小于0的分界下标,然后利用双指针,一个指针从大于等于0的地方开始(右边数组),一个从小于0的最后一位数字开始(左边数组),接着可以进行比较,然后按递增顺序放入新数组中。代码如下
class Solution {
public int[] sortedSquares(int[] nums) {
int index = 0; //定义分隔符,以此来找到数组的正负数分界下标,并作为右边数组的起始位置,一直往前走
int[] res = new int[nums.length];
for(int i = 0;i< nums.length;i++) {
if(nums[i] < 0) {
index++;
}else{
break; //找到第一个大于等于0的,直接退出循环
}
}
System.out.println(index);
int end = index - 1; //左边数组尾指针,一直往回走
int start = 0; // //新数组的索引
while(end >= 0 && index < nums.length) { //进入循环的条件
if(nums[end] * nums[end] > nums[index] * nums[index]) {
res[start] = nums[index] * nums[index]; //判断
index++;
}else {
res[start] = nums[end] * nums[end]; //判断
end--;
}
start++; //新数组下标+1
}
while(end >= 0) { //当右边数组遍历完,而左边数组没遍历完时,直接添加到新数组尾部
res[start] = nums[end] * nums[end];
start++;
end--;
}
while(index < nums.length) { //当左边数组遍历完,而右边数组没遍历完时,直接添加到新数组尾部
res[start] = nums[index] * nums[index];
index++;
start++;
}
return res;
}
}
知识点
双指针,左右指针中间的长度
注意事项
找到分解小标后,左边数组的最后一位为index - 1。最后画个例子理解。
相关题目
- 合并两个有序数组
leecode 209 长度最小的子数组
题目链接 :https://leetcode.cn/problems/minimum-size-subarray-sum/description/
题目
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其总和大于等于 target 的长度最小的 连续
子数组
[numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
示例 2:
输入:target = 4, nums = [1,4,4]
输出:1
示例 3:
输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0
解题思路
这道题可以用滑动窗口解决,一般来说,使用滑动窗口,要思考的问题是窗口内是什么,怎么移动窗口。对于这道题来说,窗口就是满足窗口数字总和sum>target的长度,我们要做的就是,在满足的窗口中,怎么去收缩窗口,使得其满足长度最小。这就是我们怎么去移动窗口,窗口的移动,有右边窗口的移动,和左边窗口的移动,一般来说,右边窗口的移动就是往窗口添加数据,而左边窗口的移动就是在满足条件的时候,不断收缩窗口。具体代码如下:
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int left = 0; //左窗口
int right = 0; //右窗口
int l = Integer.MAX_VALUE; //记录窗口的长度
int sum = 0; //窗口数字的总和
while(right < nums.length) {
sum += nums[right];
right++; //右窗口移动,往窗口添加数字
while(sum >= target) { //满足条件进入内层循环
l = Math.min(l,right - left); //记录窗口的长度
sum -= nums[left]; //
left++; //收缩窗口
}
}
return l == Integer.MAX_VALUE? 0 : l;
}
}
可能有些人疑问为什么窗口长度是l=right-left,而不是l = right - left + 1;注意上面代码是在对sum相加后,右边窗口直接向右移动了以为,在进入收缩窗口的条件循环时,此时right指向的是下一位数字,如[2,3,1,2,4,3],当窗口数字为[2,3,1,2],此时right指向的是数组的第五位(即小标为4)4,此时right = 4,left = 0,则长度为right - left = 4 - 0 = 4。那什么时候才是rigt - left + 1呢,这个情况是收缩窗口的条件循环时,right应该指向的是数组的第四位(即小标为3)4,此时l = right - left + 1 = 3 - 0 + 1 = 4。那这时候右边窗口向右移动位置应该在进入收缩窗口的条件循环代码块之后,即
while(right < nums.length) {
sum += nums[right];
while(sum >= target) { //满足条件进入内层循环
l = Math.min(l,right - left + 1); //记录窗口的长度 ,此时长度为right - left + 1
sum -= nums[left]; //
left++; //收缩窗口
}
right++; //右窗口移动,往窗口添加数字
}
知识点
滑动窗口
注意事项
怎么移动窗口,窗口内长度的记录,如何收缩窗口,进入收缩窗口的判断条件
相关题目
76.最小覆盖子串
325.和等于 k 的最长子数组长度
718.最长重复子数组
leecode 59 螺旋矩阵II
题目链接 :https://leetcode.cn/problems/spiral-matrix-ii/description/
题目
给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
示例 1:
输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]
示例 2:
输入:n = 1
输出:[[1]]
解题思路
这道题有点意思,我感觉是像涡轮一样,从外层开始,顺时针然后不断向里面卷。抛开题目给的示例来说,比如说是生成4*4的,1-16,我们按顺时针从外层开始画,然后回到位于同一纵坐标的起点,其实就是进入次外层,如题目给的示例1的8,从8开始又是重新的像上面一样画,然后再进入下一层如果还有的画),再做同样的操作。
那这么说,不就是让四个角分别收缩吗,比如up表示左上角,lower表示右下角,left表示左下角,right表示右上角。则进入下一层,不就是让up向下一层,right向左一层,lowe向上一层,left向右一层嘛。其实就是对四个角的边界值进行判断。
总的来说,就是上面的向下边靠拢,下面的往上边靠拢,右面的往左边靠拢,左面的往右边靠拢。具体代码如下:
class Solution {
public int[][] generateMatrix(int n) {
int[][] matrix = new int[n][n];//定义matrix二维数组
int count = 1; //计数器
int up = 0; //左上角
int lower = n - 1; //右下角,其实就是矩阵的行数
int left = 0; // 左下角
int right = n - 1; //右上角,其实就是矩阵的列数
while(count <= n * n) { // 终止条件为count > n * n
if(up <= lower) { //左上角 < 左下角
for(int i = left;i <= right;i++) {
matrix[up][i] = count++;
}
}
up++; //左上角不断向下靠拢
if(right >= left) { //右 > 左
for(int j = up; j <= lower;j++) {
matrix[j][right] = count++;
}
}
right--; //右上角往左边靠拢
if(lower >= up) { // 右下角 > 上
for(int i = right;i >= left;i--) {
matrix[lower][i] = count++;
}
}
lower--; //右下角不断往上靠拢
if(left <= right) { //左 < 右
for(int j = lower;j >= up;j--) {
matrix[j][left] = count++;
}
}
left++; //左下角不断往右边靠拢
}
return matrix;
}
}
###### 知识点
四个角度如何收缩进入下一层
###### 注意事项
四个角的边界判断条件和如何赋值
###### 相关题目
54. 螺旋矩阵