算法记录 02 | 977.有序数组的平方,209.长度最小的子数组,59.螺旋矩阵II

今日更新题目:977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II

977.有序数组的平方

给你一个按非递减顺序排序的整数数组 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]

提示:

  • 1 <= nums.length <= 104
  • -104 <= nums[i] <= 104
  • nums 已按 非递减顺序 排序

思路

提示中说到:nums 已按非递减顺序排序,且每个数字的平方均为正数,我的第一想法就是双指针法,很多人第一次见可能会想不出,所以在首次接触到一个新方法只需要理解并接受就好,而我是第二次见了,则应该在双指针法的基础上进一步想:两个指针从哪出发,沿着什么方向,两个指针分别在什么时候更新。下面是我有过的一些想法:

  • 先让快指针走到第一个大于等于0的位置,然后计算快慢指针所指数字的平方,比较后自增即可(看似有效,但忽略了返回的数组也要有序,按照示例1,若此时快慢指针分别位于nums[0]=-4,nums[2]=0,实际上是会出错的,原因在于要想返回的数组有序,则两个指针应在两端向中间靠近,或者是两个指针应该在nums中平方值最小的位置向两端出发,即都是较大值比较或较小值比,但是从中间出发又显得没必要,因为你要先找到nums中最接近0的数,那不如直接两边向中间靠近)
  • 两个指针从两端向中间靠近,谁索引对应的平方值更大谁更新,而返回数组则从末尾处开始更新
    在这里插入图片描述
class Solution {
public:
    // 时间复杂度为O(n)
    vector<int> sortedSquares(vector<int>& nums) {
        int k = nums.size() - 1;
        vector<int> result(nums.size(), 0);
        for(int left = 0, right = nums.size() - 1; left <= right; ){
            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;
    }
};

209.长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

示例:

  • 输入:s = 7, nums = [2,3,1,2,4,3]
  • 输出:2
  • 解释:子数组 [4,3] 是该条件下的长度最小的子数组。

提示:

  • 1 <= target <= 109
  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 105

思路

最好想的方法当然是两层for循环,复杂度为 O(n2),在每个位置尝试不同长度的子数组组合

其实审题发现,题目要求找出长度最小的连续子数组,重点在于连续,也就是有可能通过一次遍历完成,可以用滑动窗口来实现(第一次见的时候想破脑袋都想不到),那滑动窗口起始位置,结束位置该如何更新呢,for循环索引表示的是窗口的起始位置还是结束位置呢?实际上把问题转换一下就是,起始位置更新代表窗口缩小,结束位置更新代表窗口扩大,为了找出最小子数组,那自然是:

  • 窗口子数组之和 ≥ s 的时候要尝试缩小,试着找到更小的子数组;
  • 窗口子数组之和 < s 的时候要尝试扩大,试着找到勉强符合要求的子数组;
  • 至于谁是for循环里的索引,先进入for循环的当然是最先出发的,也是最先遍历完数组的,那自然是结束位置是for循环的索引。
class Solution {
public:
    // 时间复杂度:O(n),空间复杂度:O(1)
    int minSubArrayLen(int target, vector<int>& nums) {
        int result = INT32_MAX;
        int sum = 0;
        int sublength = 0;
        int left = 0;
        //滑动窗口的本质也是双指针
        for(int right = 0; right < nums.size(); right++){
            
            sum += nums[right];

            //第一次找到大于target的字串时,还不能确定是最小字串,要遍历完整个数组
            //此时应该缩小窗口,若缩小窗口后仍大于target,则窗口继续缩小(left--)
            //若缩小窗口后小于target,则应该让窗口扩大(right++)
            while(sum >= target){
                sublength = right - left + 1;
                result = result < sublength ? result : sublength;
                sum -= nums[left++];
            }
        }
        
        return result < INT32_MAX ? result : 0;
    }
};

59.螺旋矩阵II

给定一个正整数 n,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。

示例:

输入: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]

思路

这题似乎没有什么特别的算法,总的来说就是把循环过程分解实现即可,弄清楚边界即可,由于我个人不习惯去算 loop,还要用一个 offset 控制四个方向的填充,所以本题没采用代码随想录的解法,使用了 leetcode 题解里的精选解法,一图胜千言,具体思路如下,现有矩阵mat[i][j],模拟顺时针向内填充:

  • 从左到右,mat[i][j]的 i 不变,j 变,起始位置是 left,结束位置是 right,填充后上边界缩小,即top++
  • 从右到下,mat[i][j]的 i 变,j 不变,起始位置是 top,结束位置是 button,填充后右边界缩小,即right–
  • 从右到左,mat[i][j]的 i 不变,j 变,起始位置是 right,结束位置是 left,填充后下边界缩小,即button--
  • 从下到上,mat[i][j]的 i 变,j 不变,起始位置是 button,结束位置是 top,填充后左边界缩小,即left++
    在这里插入图片描述
    照着上面规则将其填入for循环即可,循环变量,起始位置,结束位置都给出了,然后再慢慢补充细节,总共 n2 步,走完即可。
class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> matrix(n, vector<int>(n, 0));
        int left = 0, right = n - 1, top = 0, button = n - 1;
        int step = 1;
        while(step <= n*n){
            // left to right
            for(int j = left; j <= right; j++)
                matrix[top][j] = step++;
            top++;

            // top to button
            for(int i = top; i <= button; i++)
                matrix[i][right] = step++;
            right--;

            // right to left
            for(int j = right; j >= left; j--)
                matrix[button][j] = step++;
            button--;

            // bottom to top
            for(int i = button; i >= top; i--)
                matrix[i][left] = step++;
            left++;
        }

        return matrix;
    }
};

引用

  1. 代码随想录 (programmercarl.com)

  2. 59. 螺旋矩阵 II - 力扣(LeetCode)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值