代码随想录算法训练营day02 | leetcode 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]

正常解法是平方后直接排序,时间复杂度是 O(n + nlogn)

数组其实是有序的, 只不过负数平方之后可能成为最大数了。

那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。

因此采用双指针法,这里需要创建一个新的数组,这里不能在原数组上进行交换,因为最大值始终在数组的两端,因此判断哪一端的值更大然后将其填充在新数组的末尾,判断完后对应的指针往中间移动。因为是对两端进行判断,所以使用左右两个指针leftright

img

代码如下:

//时间复杂度:O(n)
class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        for(int i = 0; i < nums.size(); ++i)
        {
            nums[i] = nums[i] * nums[i];
        }
        vector<int> ans(nums.size(), 0);
        int left = 0;
        int right = nums.size() - 1;
        int i = nums.size() - 1;
        while(left <= right)
        {
            if(nums[left] > nums[right])
            {
                ans[i] = nums[left];
                ++left;
            }
            else if(nums[left] <= nums[right])
            {
                ans[i] = nums[right];
                --right;
            }
            --i;
        }
        return ans;
    }
};

题目链接:209. 长度最小的子数组-中等

题目描述:给定一个含有 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

方法一:滑动窗口

209.长度最小的子数组

代码如下:

//时间复杂度:O(n)
//空间复杂度:O(1)
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int i = 0; // 滑动窗口起始位置
        int sum = 0; // 滑动窗口数值之和
        int res = 1e9;
        int len = 0; // 滑动窗口的长度
        for(int j = 0; j < nums.size(); ++j)
        {
            sum += nums[j];
            while(sum >= target)
            {
                len = j - i + 1; // 子序列的长度
                res = res < len ? res : len; //更新最小的长度
                sum -= nums[i];
                ++i;
            }
        }
        // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
        return res == 1e9 ? 0 : res;
    }
};

方法二:前缀和+二分法

代码如下:

//时间复杂度:O(nlogn)
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        vector<int> sums(nums.size() + 1, 0);
        if (nums.size() == 0) {
            return 0;
        }
        for(int i = 1; i <= nums.size(); ++i)
        {
            sums[i] = sums[i - 1] + nums[i - 1]; // 前缀和
        }
        if(sums[nums.size()] < target) // 所有值加起来小于目标值
            return 0;
        int ans = INT32_MAX;
        for(int j = 1; j < sums.size(); ++j)
        {
            int temp = target + sums[j - 1]; // 前缀和加上目标序列的值
            // 在剩余序列中采用二分法寻找最小的大于等于temp的前缀和
            int left = j;
            int right = sums.size();
            while(left < right)
            {
                int mid = left + ((right - left) >> 1);
                if(sums[mid] >= temp)
                {
                    ans = ans < (mid - j + 1) ? ans : (mid - j + 1);
                    right = mid;
                }
                else
                    left = mid + 1;
            }
            
        }
        return ans == INT32_MAX ? 0 : ans;
    }
};

题目链接:59. 螺旋矩阵 II-中等

题目描述:

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

示例 1:

img

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

示例 2:

输入:n = 1
输出:[[1]]

代码如下:

//时间复杂度 O(n^2): 模拟遍历二维矩阵的时间
//空间复杂度 O(1)
class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> mat(n, vector<int>(n, 0)); // 使用vector定义一个二维数组
        int loop = n / 2; // 每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理
        int count = 1;
        int edge = 1; // 边缘厚度,每循环一个圈后厚度+1
        int startx = 0, starty = 0; // 定义每循环一个圈的起始位置
        int i, j;
        while(loop--)
        {
            // 下面开始的四个for就是模拟转了一圈,遵循左开右闭原则
            for(j = starty; j < n - edge; ++j)
            {
                mat[startx][j] = count++;
            }
            for(i = startx; i < n - edge; ++i)
            {
                mat[i][j] = count++;
            }
            for(; j > starty; --j)
            {
                mat[i][j] = count++;
            }
            for(; i > startx; --i)
            {
                mat[i][j] = count++;
            }
            // 第二圈开始的时候,起始位置要各自加1
            ++startx;
            ++starty;
            // 第二圈开始的时候,边缘厚度加1
            ++len;
        }
        // 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
        if(n % 2)
        {
            mat[n / 2][n / 2] = n * n;
        }
        return mat;
    }
};
posted @ 2024-02-22 19:59  Humphreyr  阅读(62)  评论(0编辑  收藏  举报