代码随想录算法训练营第二天| Leetcode 977、Leetcode 209、Leetcode 59
打卡
Leetcode 977 有序数组的平方
题目链接
本题提示用双指针求解,想了半天都没想明白双指针该怎么排序还以为是冒泡排序那种,看了代码随想录后恍然大悟,发现自己对原数组为“非递减顺序”缺乏敏感,原数组有序意味着平方的大项在数组两端出现而且向中心递减,因而可以用相向指针跟踪大值完成排序
解答
class Solution {
public int[] sortedSquares(int[] nums) {
// 双指针法
int left = 0;
int right = nums.length - 1;
int result[] = new int[nums.length];
for (int index = nums.length - 1; index > -1; index--){
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;
}
}
Leetcode 209 长度最小的子数组
暴力法用两个for循环分别移动起始位置和终止位置,滑动窗口则只采用一个for循环(指向终止位置,指向起始位置则回到了暴力法),其精髓在于如何移动起始位置。
当窗口边界不断扩大至满足>=s的条件时,更新result并且起始位置不断右移尝试缩小窗口最终找到长度最小的子数组。
该做法虽然也有两层循环,不过数组中每一个元素都只有出窗口和入窗口两次操作,所以复杂度仅为O(n)
解答
class Solution {
public int minSubArrayLen(int target, int[] nums) {
// 滑动窗口
int left = 0;
int sum = 0;
int result = Integer.MAX_VALUE;
for (int right = 0; right < nums.length; right++) {
// 滑动之后先更新sum,然后判断
sum += nums[right];
while (sum >= target){
result = Math.min(result, right - left + 1);//比较result和滑动窗口大小
sum -= nums[left++];
}
}
return result == Integer.MAX_VALUE?0:result;
}
}
(不过如果题干不是全正数的话。。。)
Leetcode 59 螺旋矩阵
题目链接
此题模拟螺旋矩阵的过程。最开始还打算一条边堆到底然后用一个flag调转方向继续该过程。。上学上3年反而把最基础的编程思维丢掉了,我这学上得属实有点失败(不过现在来看,一开始的想法可能是以“转角”作循环不变量,但是该循环过程中边长n:n-1:n-1:n-2的变化或者每3次变化一次和推荐答案比起来差距确实大)
此题精髓在于抓住循环不变量。把画圈过程拆解成画4条左闭右开的线,用统一的规则画圈。
解答
class Solution {
public int[][] generateMatrix(int n) {
int[][] nums = new int[n][n];
int startX = 0, startY = 0; //每一圈起始点
int offset = 1; // 边界的偏移量
int count = 1;
int i = 0, j = 0; // i表示行, j表示列
int size = n; // 需要画圈的大小,n不能变动
while (size /2 != 0){
//顶部
for (j = startY; j < n-offset; j++){
nums[startX][j] = count++;
}
//右侧
for (i = startX; i < n-offset; i++){
nums[i][j] = count++;
}
//底部
for (; j > startY; j--){
nums[i][j] = count++;
}
//左侧
for (; i > startX; i--){
nums[i][j] = count++;
}
//过渡到下一圈
startX++;
startY++;
offset++;
size -= 2;
}
//n为奇数的情况
if (size == 1) nums[startX][startY] = count;
return nums;
}
}