刷刷刷Day2| 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II
977.有序数组的平方
LeetCode题目要求
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
示例 1:
输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]
解题思路
由于给定的数组是有序且非递减(递增),而元素可能为负数,所以需要再平方后再排序
- 思路1,先平方,再进行排序
class Solution {
public int[] sortedSquares(int[] nums) {
// 有序数组,非递减(递增),可能存在负数,平方后不一定是有序,因此需要再排序
for (int i = 0; i < nums.length; i++) {
int t = nums[i];
nums[i] = t * t;
}
// 使用 Arrays.sort(int[]) 进行自然顺序排序
Arrays.sort(nums);
return nums;
}
}
- 思路2,双指针
class Solution {
public int[] sortedSquares(int[] nums) {
// 双指针怎么解决呢
// 输入:nums = [-4,-1,0,3,10]
// 输出:[0,1,9,16,100]
// 思路:遍历数组,做平方操作,平方后,如果值比后面的大,就与后面的交换
int left = 0; // 左指针
int right = nums.length - 1; // 右指针
int[] result = new int[nums.length]; // 存储平方排序后的结果
int k = right; // k 与 right 相等,从 k 位置开始放值
while (left <= right) {
//如果左指针平方 小于 右指针平方值,那么将大的值,放到 result k 的位置
if (nums[left] * nums[left] < nums[right] * nums[right]) {
result[k--] = nums[right] * nums[right];
right--;
} else {
result[k--] = nums[left] * nums[left];
left++;
}
}
return result;
}
}
重难点
双指针是个巧妙的解法,而且通过一个循环+指针移动就完成了。需要主要的点是:
- while(left<=right) 这里使用的 <=, 需要和 right 的取值对应。
- 指针移动,通过对比平方值,大的往右放,小的放左边
附:学习资料链接
209.长度最小的子数组
LeetCode题目要求
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
解题思路
- 双指针,通过两个指针的移动,指针对应的值相加如果与 target 相等,记录两个指针间的长度。
这个解法在 LeetCode 上跑居然超时了, 之前可以正常执行,很神奇
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int i = 0;
int j = 0;
int len = nums.length;
int result = Integer.MAX_VALUE;
/* 分析过程
0 1 2 3 4 5
2, 3, 1, 2, 4, 3
i j 2+3=5 < 7 下一次移动 j
i j 2+3+1=6 < 7 这里移动 j
i j 2+3+1+2=8>7 下一次移动 i
i j 3+1+2=6 < 7 这里移动 i
i j 3+1+2+4=10 > 7 下一次移动 i
i j 1+2+4=7 下一次移动i,与 target 相等,记录 j-i+1 = 4-2+1 = 3
i j 2+4=6 < 7 这里移动 i,下一次移动 j
i j 2+4+3=9 > 7 这里移动 j,下一次移动 i
i j 4+3=7 这里移动 i,与 target 相等, 记录 j-i+1= 5-4+1 = 2, 比前值小,返回
*/
while(i <= j && j < len) {
int sum = calc(nums, i, j);
if (sum >= target) {
int l = j - i + 1;
result = l < result ? l : result;
i++;
} else if (sum < target) {
j++;
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
private int calc(int[] nums, int i, int j) {
int sum = 0;
for(; i <= j; i++) {
sum += nums[i];
}
return sum;
}
}
- carl 解法,滑动窗口
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int left = 0;
int sum = 0;
int result = Integer.MAX_VALUE;
// 遍历数组,过程中通过 left 与 right 指针形成一个滑动的窗口
for (int right = 0; right < nums.length; right++) {
// right 指针计算 每个滑动过的值的和
sum += nums[right];
// 如果滑动过的所有元素的和 大于等于 target ,那么就找到了
while (sum >= target) {
// 判断上一次的 result(窗口大小) 与当前窗口大小相比,取小的
result = Math.min(result, right - left + 1);
// 重新计算窗口内的和,但此时的操作是 将 left 指针右移,并且 sum 中把 left 指针的值减去,下一次再判断是否大于等于 target。
sum -= nums[left++];
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
}
重难点
需要理解滑动窗口的思想:与双指针类似,通过两个指针形成一个窗口,然后通过移动左右指针,变换窗口的大小,形成与目标值匹配的大小
附:学习资料链接
59.螺旋矩阵II
LeetCode题目要求
给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
示例:
输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]
解题思路
根据题目,需要输出的是一个 int[n][n] 的二位数组,那么输出时需要模拟成一个顺时针的螺旋,输出方式为 从左到右 --> 从上到下 --> 从右到左 --> 从下到上,如此重复,直到输出为 n/2 圈;
代码实现
class Solution {
public int[][] generateMatrix(int n) {
int[][] result = new int[n][n];
int startX = 0, startY = 0; // 每循环一圈的起始位置
int loop = 0; //控制循环次数
int mid = n / 2; // 矩阵中间位置
int count = 1; // 填充数值
int offset = 1; // 控制每个边遍历的长度,每次循环右边界收缩一位
int i, j;
while (loop++ < n / 2) { // 螺旋次数
i = startX;
j = startY;
// 从左到右 左闭右开
for (j = startY; j < n - offset; j++) {
result[startX][j] = count++;
}
// 从上倒下 上闭下开
for (i = startX; i < n - offset; i++) {
result[i][j] = count++;
}
// 从右到左 右闭左开
for (; j > startY; j--) {
result[i][j] = count++;
}
// 从下到上 下闭上开
for (; i > startX; i--) {
result[i][j] = count++;
}
startX++;
startY++;
offset++;
}
if (n % 2 == 1) {
result[mid][mid] = count;
}
return result;
}
}
重难点
- 确定好边界条件,需要注意的就是输出时,始终保持的是 闭开 原则,从开始到结束的形式为:左闭右开-> 上闭下开-> 右闭左开 -> 下闭上开
- 如果 n 是奇数时,要对中间的点进行补充输出,才是完整的
附:学习资料链接