代码随想录算法训练营第二天| 977.有序数组的平方、209.长度最小的子数组、59.螺旋矩阵II
977.有序数组的平方
题目建议: 本题关键在于理解双指针思想
题目链接:https://leetcode.cn/problems/squares-of-a-sorted-array/
文章讲解:https://programmercarl.com/0977.%E6%9C%89%E5%BA%8F%E6%95%B0%E7%BB%84%E7%9A%84%E5%B9%B3%E6%96%B9.html
视频讲解: https://www.bilibili.com/video/BV1QB4y1D7ep
思路想法:1)非递减排好的数组,则非负数部分直接返回数字平方值就为非递减顺序
2)负数部分,由于也是按非递减排列,则直接平方后为非递增顺序
3)需要考虑,将负数部分的平方插入到非负数平方返回后的数组中合适位置
然而写不出来.....
暴力:
第 1 步:一层 for 循环遍历数组,将各元素平方后存入数组,这一步的时间复杂度为 O(n)。
第 2 步:快排,时间复杂度为 O(nlogn)。
总的时间复杂度显然是 O(n + nlogn)
class Solution {
public int[] sortedSquares(int[] nums) {
for(int i= 0;i< nums.length;i ++){
nums[i] *=nums[i];
}
Arrays.sort(nums);
return nums;
}
}
双指针
思路:
数组其实是有序的, 只不过负数平方之后可能成为最大数了。
那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。
此时可以考虑双指针法了,i指向起始位置,j指向终止位置。
定义一个新数组result,和A数组一样的大小,让k指向result数组终止位置。
看思路自己写,然后调试,code如下:
class Solution {
public int[] sortedSquares(int[] nums) {
int[] sortedNums = new int[nums.length];
int left = 0;
int right = nums.length - 1;
int index = nums.length - 1;
while(left <= right){
if(nums[left] * nums[left] < nums[right] * nums[right]){
sortedNums[index] = nums[right] * nums[right];
right --;
}else{
sortedNums[index] = nums[left] * nums[left];
left ++;
}
index --;
}
return sortedNums;
}
}
参考答案:
class Solution {
public int[] sortedSquares(int[] nums) {
int right = nums.length - 1;
int left = 0;
int[] result = new int[nums.length];
int index = result.length - 1;
while (left <= right) {
if (nums[left] * nums[left] > nums[right] * nums[right]) {
// 正数的相对位置是不变的, 需要调整的是负数平方后的相对位置
result[index--] = nums[left] * nums[left];
++left;
} else {
result[index--] = nums[right] * nums[right];
--right;
}
}
return result;
}
}
学习简洁的代码
class Solution {
public int[] sortedSquares(int[] nums) {
int l = 0;
int r = nums.length - 1;
int[] res = new int[nums.length];
int j = nums.length - 1;
while(l <= r){
if(nums[l] * nums[l] > nums[r] * nums[r]){
res[j--] = nums[l] * nums[l++];
}else{
res[j--] = nums[r] * nums[r--];
}
}
return res;
}
}
209.长度最小的子数组
题目建议: 本题关键在于理解滑动窗口
题目链接:https://leetcode.cn/problems/minimum-size-subarray-sum/
视频讲解:https://www.bilibili.com/video/BV1tZ4y1q7XE
思路想法:
滑动窗口,窗口值初始为1,逐渐递增,自左向右滑动,查看窗口内之和是否满足条件
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int win = 1;
while (win < nums.length + 1){
for(int l = 0;(l + win -1 ) < nums.length;l ++){
int r = l + win -1;
int res = 0;
while(l <= r){
res += nums[l++];
if(res >= target){
return win;
}
}
}
return 0;
}
}
超时
在本题中实现滑动窗口,主要确定如下三点:
- 窗口内是什么?
- 如何移动窗口的起始位置?
- 如何移动窗口的结束位置?
窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。
窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)。
窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int res = Integer.MAX_VALUE;
int left = 0;
int sum = 0;
for(int right = 0;right < nums.length;right++){
sum += nums[right];
while(sum >= target){
res = Math.min(res,right - left + 1);
sum -= nums[left++];
}
}
return res == Integer.MAX_VALUE ? 0 : res;
}
}
- 时间复杂度:O(n)
- 空间复杂度:O(1)
总结:知道大概思路,写不出来=。=
59.螺旋矩阵II
题目建议: 本题关键还是在转圈的逻辑,在二分搜索中提到的区间定义,在这里又用上了。
题目链接:https://leetcode.cn/problems/spiral-matrix-ii/
文章讲解:https://programmercarl.com/0059.%E8%9E%BA%E6%97%8B%E7%9F%A9%E9%98%B5II.html
视频讲解:https://www.bilibili.com/video/BV1SL4y1N7mV/
想法思路:
n行n列,自左向右:第一行为1到n;自上到下:第n列为n到2n-1(n+n-1); 自右向左:第n行为2n-1(n+n-1)到3n-2(n+n-1+n-1);自下到上:第一列为3n-2(n+n-1+n-1)到4n-4(n+n-1+n-1 + n-1-1)
不会
看答案:左闭右开、左闭右开、左闭右开!!!
转n/2圈,
class Solution {
public int[][] generateMatrix(int n) {
int loop = 0; // 控制循环次数
int[][] res = new int[n][n];
int start = 0; // 每次循环的开始点(start, start)
int count = 1; // 定义填充数字
int i, j;
while (loop++ < n / 2) { // 判断边界后,loop从1开始
// 模拟上侧从左到右
for (j = start; j < n - loop; j++) {
res[start][j] = count++;
}
// 模拟右侧从上到下
for (i = start; i < n - loop; i++) {
res[i][j] = count++;
}
// 模拟下侧从右到左
for (; j >= loop; j--) {
res[i][j] = count++;
}
// 模拟左侧从下到上
for (; i >= loop; i--) {
res[i][j] = count++;
}
start++;
}
if (n % 2 == 1) {
res[start][start] = count;
}
return res;
}
}
先打个卡,2022年11月18日00:39:31,明天再研究

浙公网安备 33010602011771号