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

文章介绍了LeetCode上的几道经典算法题目的解决方案,包括使用双指针法解决有序数组的平方问题,以及运用滑动窗口找到长度最小的子数组,最后讨论了如何生成螺旋矩阵的算法。这些方法注重效率,时间复杂度低,适合面试和提高编程技巧。
摘要由CSDN通过智能技术生成

LeetCode 977 有序数组的平方

题目链接:977

解1:暴力

思路:先求每个值的平方,再对数组进行排序

分析:时间复杂度为O(n+nlogn),即O(nlogn)

代码:

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {

        for (int i=0; i<nums.size(); ++i) {
            nums[i] = nums[i] * nums[i];
        }

        std::sort(nums.begin(), nums.end());

        return nums;

    }

};

解2:双指针法

思路:由于原数组为非递减顺序,因此若将数组根据正负分为两段,则平方后,前段递减,后段递增,因此最大值一定为最左值或最右值。选出最大值填入新数组的末尾,剩下的子数组的最大值仍为子数组的最左值或最右值,因此可不断迭代。

分析:时间复杂度为O(n)

代码:

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {

        vector<int> res(nums.size(), 0);

        // left, right指向原数组两侧
        // k指向新数组的待写入位置
        int left = 0;
        int right =  nums.size() - 1;
        int k = right;

        while (left <= right) {
            int left_square = nums[left] * nums[left] ;
            int right_square = nums[right] * nums[right];

            // 由于当前范围内的最大值只能由left或right指向,因此只需考虑这两者即可
            if (left_square >= right_square) {
                res[k--] = left_square;
                ++left;
            } else {
                res[k--] = right_square;
                --right;
            }
        }

        return res;

    }
};

LeetCode 209 长度最小的子数组

题目链接:209

滑动窗口法

思路:通过滑动窗口寻找满足sum大于target的子串。当sum小于target时,移动右边界直至找到满足要求的子串;当sum大于等于target时,尝试移动左边界以缩小子串长度,寻找右边界固定时符合要求的最小子串长度。

分析:时间复杂度O(n)

代码1:此为自己写的版本,在while循环中,每次只移动左边界或右边界一个单位

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        // fast, slow定义滑动窗口的边界
        int fast = 0;
        int slow = 0;
        int res = INT32_MAX;
        int sum = nums[slow];
        bool fast_flag;

        while (fast < nums.size()){
            // 为防止fast越界,在前次迭代++fast之后先不加nums[fast]
            // 在判断fast在范围内后,再将其加入sum
            if (fast_flag) sum += nums[fast];

            if (sum >= target) {
                // 若和大于target,则左边界右滑,尝试更短的子串
                int num = fast - slow + 1;
                if (num < res) res = num;
                sum -= nums[slow++];
                fast_flag = false;
            } else {
                // 若和小于target,则右边界右滑,尝试更长的子串
                ++ fast;
                fast_flag = true;
            }
        }

        if (res < INT32_MAX) {
            return res;
        }

        return 0;

    }
};

代码2:此为参考题解后写的版本,for循环右边界,对于每个固定的右边界,移动左边界,寻找最小的符合要求的子串长度

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        // fast, slow定义滑动窗口的边界
        int fast = 0;
        int slow = 0;
        int res = INT32_MAX;
        int sum = 0;

        for (fast; fast < nums.size(); ++fast) {
            sum += nums[fast];

            // 固定fast,若sum大于target,则尝试右滑slow
            // 缩短子串长度
            while (sum >= target) {
                int num = fast - slow + 1;
                if (num < res) res = num;
                sum -= nums[slow++];
            }

        }

        return res==INT32_MAX ? 0 : res;

    }
};

LeetCode 59 螺旋矩阵II

题目链接:59

思路:将目标矩阵分层,从外到内一圈为一层,对于每一层,按上行-右列-下行-左列的顺序填数,机按螺旋顺序填数

代码1:此为自己写的版本,每条边的边界条件不一致,逻辑上较为不清晰,但不需要针对奇数维矩阵单独填入中间数

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {

        int num = 0;
        vector<vector<int>> mat(n, vector<int>(n));

        // 每个level可理解为1圈
        // 若n为奇数,则中间的值单独成圈
        for  (int level=0; level < (n+1)/2; ++level) {

            //填充上行
            for (int i=level; i<=(n-level-1); ++i)
                mat[level][i] = ++num;

            //填充右列
            for (int i=level+1; i<=(n-level-1); ++i)
                mat[i][n-1-level] = ++num;

            //填充下行
            for (int i=n-level-2; i>=level; --i)
                mat[n-1-level][i] = ++num;

            //填充左列
            for (int i=n-2-level; i>=level+1; --i)
                mat[i][level] = ++num;
        }

        return mat;

    }
};

代码2:此为参考代码随想录后写的版本,四条边的遍历规则都为左闭右开,但需要针对奇数维矩阵单独填入中间数

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {

        vector<vector<int>> mat(n, vector<int>(n, 0));

        int level = n / 2;
        int start_x = 0;
        int start_y = 0;
        int num = 0;

        while (level > 0 ) {
            int i = start_y;
            int j = start_x;

            for (j; j < n-1-start_x; ++j)
                mat[i][j] = ++num;

            for (i; i < n-1-start_y; ++i)
                mat[i][j] = ++num;

            for (j; j > start_x; --j)
                mat[i][j] = ++num;

            for (i; i > start_y; --i)
                mat[i][j] = ++num;
            
            ++start_x;
            ++start_y;
            --level;
        }

        if (n % 2 != 0) {
            int mid = n/2;
            mat[mid][mid] = ++num;
        }

        return mat;

    }
};

代码3:此为参考LeetCode高赞题解版本。设置上下左右四条边界,按上右下左顺序填充,每填充完一条边界的值,则移动边界。代码逻辑清晰,且无需针对奇数矩阵做额外处理。

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {

        vector<vector<int>> mat(n, vector<int>(n, 0));
        int num = 1;

        // 上下左右边界
        int top = 0;
        int bottom = n-1;
        int left = 0;
        int right = n-1;

        while (num <= n*n) {
            for (int i=left; i<=right; ++i)
                mat[top][i] = num++;
            ++top;

            for (int i=top; i<=bottom; ++i) 
                mat[i][right] = num++;
            --right;

            for (int i=right; i>=left; --i)
                mat[bottom][i] = num++;
            --bottom;

            for (int i=bottom; i>=top; --i)
                mat[i][left] = num++;
            ++left;
                
        }


        return mat;

    }
};

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值