代码随想录算法训练营第二天 | 977.有序数组的平方、209.长度最小的子数组、59.螺旋矩阵Ⅱ

977.有序数组的平方

文章链接:977.有序数组的平方
视频链接:双指针法经典题目 | LeetCode:977.有序数组的平方

题目描述
977.有序数组的平方

题解

解法一:暴力法

将各元素平方后令数组进行排序。

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        for(int i = 0; i < nums.size(); i++) {
            nums[i] = nums[i] * nums[i];
        }

        sort(nums.begin(), nums.end());
        return nums;
    }
};

时间复杂度:O(n + nlogn)
空间复杂度:O(1)

解法二:双指针法

由于数组有序排列且包含负数,以[-3, -2, -1, 0, 1, 2, 3]为例,数组平方最大值仅可能位于数组左端或右端。
令i指针指向数组左端,j指针指向数组右端,分别比较两元素平方,将较大值置于新数组右端后将该指针向中间移动一位,以此类推直至i > j。

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        int k = nums.size() - 1;
        vector<int> result(nums.size(), 0);
        for (int i = 0, j = nums.size() - 1; i <= j;) {
            if (nums[i] * nums[i] < nums[j] * nums[j])  {
                result[k] = nums[j] * nums[j];
                k--;
                j--;
            }
            else {
                result[k] = nums[i] * nums[i];
                k--;
                i++;
            }
        }
        return result;
    }
};

时间复杂度:O(n)
空间复杂度:O(n)

209.长度最小的子数组

文章链接:290.长度最小的子数组
视频链接:拿下滑动窗口! | LeetCode 209 长度最小的子数组

题目描述
290.长度最小的子数组

题解

解法一:暴力法

通过双层for循环遍历任意两元素组成的所有区间,比较得出满足元素和大于等于target的最小区间长度。

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int sum, len, minLen = INT_MAX;

        for(int i = 0; i < nums.size(); i++) {
            sum = 0;

            for(int j = i; j < nums.size(); j++) {
                sum += nums[j];
                if(sum >= target) {
                    len = j - i + 1;
                    if(len < minLen) minLen = len;
                    break;
                }
            }
        }

        return minLen == INT_MAX ? 0 : minLen;
    }
};

时间复杂度:O(n^2)
空间复杂度:O(1)

解法二:滑动窗口(双指针法)

  1. 令j指向区间终止位置,i指向区间起始位置。
  2. 以终止位置j作为for循环索引。遍历以j为终点的各区间,区间各元素之和为sum。
  3. 外层for循环j由左至右遍历数组各元素。若sum大于等于target,则计算区间长度len并与最短区间长度minLen进行比较,len小于等于minLen则更新minLen并左移i,重复上述过程直至sum小于target,则左移j,以此类推直至j = nums.size()。
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int i = 0, len, minLen = INT_MAX, sum = 0;

        for(int j = 0; j < nums.size(); j++) {
            sum += nums[j];

            while(sum >= target) {
                len = j - i + 1;
                if(len <= minLen) {
                    minLen = len;
                }
                sum -= nums[i];
                i++;
            }
        }
        return minLen == INT_MAX ? 0 : minLen;
    }
};

时间复杂度:O(n)
空间复杂度:O(1)
j总共移动n次,i在最坏情况下也移动n次,故时间复杂度为O(2n),省略常数项系数后时间复杂度为O(n)。

另:
4. LeeCode解答错误代码及其错误原因。

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int i, len, minLen = INT_MAX, sum = 0; 
        // 应于此处令i = 0,i最初指向最左端元素,往后i仅向右移动,不再回溯。

        for(int j = 0; j < nums.size(); j++) {
            i = 0; 
            /*
            	执行失败, 应删除该行代码,并在进入该循环前令i = 0。
            	以target = 7,[2, 3, 1, 2, 4, 3]为例,第一次更新minLen时为i = 0,j = 3,sum = 8
            	执行一次sum -= sum[0]后sum = 6,sum < target跳出循环时i重新指向最左端元素,
            	此时sum并非i = 0, j = 4对应区间和,而是i = 1,j = 3对应区间和。
            	且若每次循环i重置为0并逐个计算sum,则该算法时间复杂度为O(n^2),不再为线性时间复杂度。
            */
            sum += nums[j];

            while(sum >= target) {
                len = j - i + 1;
                if(len < minLen) {
                     minLen = len;
                }

                sum -= nums[i];
                i++;
            }
        }

        return minLen == INT_MAX ? 0 : minLen;
    }
};

59.螺旋矩阵Ⅱ

文章链接:59.螺旋矩阵Ⅱ
视频链接:一入循环深似海 | LeetCode:59.螺旋矩阵II

题目描述
59.螺旋矩阵Ⅱ

题解
本题不涉及任何算法,即模拟题目求解过程。
应遵循循环不变量原则。本题不变量为各边处理规则,各边均遵循左闭右开(即各边最后一个节点由下一条边进行处理)。

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> res(n, vector<int>(n, 0));
        int startX = 0, startY = 0; // 起始位置为res[startX][startY]
        int loop = n / 2;
        int offset = 1; // 每次循环遍历至所在边的第n - offset个结点
        int i, j; // 二维矩阵res[i][j]
        int count = 1;

        while(loop--) {
        	// 由左至右
            for(j = startY; j < n - offset; j++) {
                res[startX][j] = count++; 
            }
            // 由上至下
            for(i = startX; i < n - offset; i++) {
                res[i][j] = count++;
            }
            // 由右至左
            for(;j > startY; j--) {
                res[i][j] = count++;
            }
            // 由下至上
            for(;i > startX; i--) {
                res[i][j] = count++;
            }

			// 遍历下一圈
            startX++; 
            startY++;
            offset++;
        }
        
        if(n % 2) {
            res[n/2][n/2] = count;
        }

        return res;
    }
};

时间复杂度:O(n^2)
空间复杂度:O(1)
该题本质上即遍历二维矩阵,时间复杂度为O(n^2)。

后记
啊总算又一天。:’
第二题因为找bug搁置了好久。
对代码的执行细节掌握得不太好呢,加油加油。

待完成

  1. vector与array的区别。
  2. 76.最小覆盖子串
  3. 27.移除元素相向双指针法。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值