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

977.有序数组的平方

思路:数组是非递减的,因此数组的单调性呈V形,数组平方的最大值肯定出现在边界,所以我们可以对边界进行检查,将平方数大的插入新的数组的尾部。

问题:
可能受到了移除元素那题的影响,刚开始一直把自己局限在空间复杂度O(1)且时间复杂度O(N)的方法(即只在原数组进行操作),最后才发现不可行浪费时间。
算法完成过程中可能是写迷糊了,犯了很多低级错误,包括比较条件没用平方,进行操作后两个指针没有更新。说明在检查过程没有行程统一的习惯。

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

209. 长度最小的子数组

思路

题目要求是连续子数组,所以可以考虑用滑动窗口解决。通过增长和缩短窗口区间来实现符合要求的连续数组的遍历。不断增长让窗口符合条件(sum >= target)然后缩短窗口破坏条件使得(sum < target),一旦不满足条件继续增长。要仔细考虑边界条件和特殊情况。

问题

忘了考虑特殊情况!当tail等于n且sum不超过target时就可以结束循环,但如果整个数组加起来都没超过target,相当于在循环过程中没进行min_len的更新,那么会返回INT_MAX,所以要特殊处理。

class Solution {
public:
    //题目要求是连续子数组,所以可以通过增长缩短区间
    //sum超过target就从头部缩短,没超过就加长尾部
    //记录最小数组长度
    //[head, tail)
    int minSubArrayLen(int target, vector<int>& nums) {
        int min_len = INT_MAX;
        int head = 0;
        int tail = 0;
        int sum = 0;
        //尾部正常访问数据
        while (tail <= nums.size()){
            if (sum < target) {
                if (tail == nums.size()) {
                    break;
                }
                sum += nums[tail++];
            }
            if (sum >= target){
                if (tail - head < min_len){
                    min_len = tail - head;
                }
                sum -= nums[head++];
            }
        }
        if (min_len == INT_MAX) return 0;
        return min_len;
    }
};

代码优化

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int min_len = nums.size() + 1;
        int head = 0;
        int sum = 0;
        // Use a for loop for clarity and to avoid off-by-one errors.
        for (int tail = 0; tail < nums.size(); tail++) {
            sum += nums[tail];
            while (sum >= target) {
                int len = tail - head + 1;
                if (len < min_len) {
                    min_len = len;
                }
                sum -= nums[head++];
            }
        }
        return (min_len > nums.size()) ? 0 : min_len;
    }
};

59. 螺旋矩阵 II

思路:顺时针由四个循环的方向组成,可以考虑用取余实现方向的转换,方向转换的边界条件判断:

  1. 超出数组的边界条件
  2. 下一步要走的位置已经被走过,即 != 初始值

每次走一步(赋值),并且确定下一步的位置(方向的判断和转换)

问题:小错误,0,1,2,3是对4取余,不是对3取余

class Solution {
public:
    // +c, +r, -c, -r
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> result (n, vector<int>(n, -1));
        int dir = 0;
        int i = 0;
        int j = 0;
        int p = 0;
        for (int k = 1; k <= n * n; ++k) {
            result[i][j] = k;
            if (dir == 0){
                if (j + 1 >= n) turn_dir(dir);
                else if (result[i][j+1] != -1) turn_dir(dir);
                update_ij_by_dir(i, j, dir);
            }
            else if (dir == 1) {
                if (i + 1 >= n) turn_dir(dir);
                else if (result[i+1][j] != -1) turn_dir(dir);
                update_ij_by_dir(i, j, dir);
            }
            else if (dir == 2){
                if (j - 1 < 0) turn_dir(dir);
                else if (result[i][j-1] != -1) turn_dir(dir);
                update_ij_by_dir(i, j, dir);
            }
            else if (dir == 3){
                if (i - 1 < 0) turn_dir(dir);
                else if (result[i - 1][j] != -1) turn_dir(dir);
                update_ij_by_dir(i, j, dir);
            }
        }
        return result;
    }
    void update_ij_by_dir(int& i, int& j, int dir){
        if (dir == 0) ++j;
        else if (dir == 1) ++i;
        else if (dir == 2) --j;
        else if (dir == 3) --i;
    }
    void turn_dir(int& dir){
        dir = (dir + 1) % 4;
    }
};


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值