算法训练营Day2 数组part2

文章介绍了三种编程算法问题的解决方案:一是有序数组的平方,使用双指针优化暴力排序;二是寻找长度最小的子数组,通过滑动窗口法降低时间复杂度;三是构建螺旋矩阵的两种方法,包括模拟和通用解法,强调了边界条件的处理。
摘要由CSDN通过智能技术生成

第一题

977.有序数组的平方

        ①暴力解法:将数组中每个元素平方后再排序;

        ②双指针解法:数组中有负数,所以平方后最大的数字可能出现在数组的左右两侧位置,且左右两侧数字的平方一定大于中间数字的平方。因此,我们可以设置两个指针left和right分别指向数组的首尾两侧,比较平方后较大的数字,插入新数组的末尾,然后移动指针继续比较,直到将原先数组的平方全部放入新数组中为止。

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

第二题

209.长度最小的子数组

        ①暴力解法:两次for循环,时间复杂度为O(^{}n^{2});

        ②滑动窗口法:一次for循环解决问题,只需对滑动窗口的右边界进行for循环,左边界则动态的更新,时间复杂度为O(n)。

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int sum = 0, res = INT_MAX;
        for(int i = 0, j = 0; j < nums.size(); j++){
            sum += nums[j];
            while(sum >= target){
                int subLength = j - i + 1;
                res = min(res,subLength);
                sum -= nums[i];
                i++;
            }
        }
        if(res == INT_MAX)
            return 0;
        return res;
    }
};

第三题

59.螺旋矩阵Ⅱ

        这道题通过模拟法解决,要注意判断边界问题。

      模拟顺时针画矩阵的过程如下:

  • 填充上行从左到右
  • 填充右列从上到下
  • 填充下行从右到左
  • 填充左列从下到上

        ①循环不变量方法:每次填充相同的数量,按照左闭右开区间,即:[)的方式进行,如下图所示,每次移动相同的位置,下一个边界处本次移动不处理。还需要注意的是,当n为基数时,需要手动添加中间那个位置的元素!

        

        

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> res(n,vector<int>(n,0));
        int startx = 0, starty = 0, count = 1;
        int offset = 1;
        int mid = n / 2;
        int time = mid;
        while(time-- > 0){
            int i = startx, j = starty;
            for(; j < n - offset; j++){
                res[i][j] = count++;
            }
            for(; i < n - offset; i++){
                res[i][j] = count++;
            }
            for(; j > offset - 1; j--){
                res[i][j] = count++;
            }
            for(; i > offset - 1; i--){
                res[i][j] = count++;
            }
            offset++;
            startx++;
            starty++;
        }
        if(n % 2 == 1){
            res[mid][mid] = count;
        }
        return res;
    }
};

         ②一种更为通用的解法:来源于54题螺旋矩阵高赞题解的思路。是一种更加通用的解法,能够解决m*n这种一般矩阵的问题,不必非得是n*n矩阵。

本质思想是:每次移动后改变边界,并判断边界条件不在满足逻辑关系,不满足便跳出循环。

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> res(n,vector<int>(n,0));
        //分别定义上下左右侧的边界
        int up = 0;
        int down = n - 1;
        int left = 0;
        int right = n - 1;
        //a为添加到matrix相应位置的数字
        int a = 1;
        while(1){
            //1.1向右移动
            for(int j = left; j <= right; j++){
                res[up][j] = a++;
            }
            //1.2重新定义上边界,若上边界超出下边界,则跳出循环
            if(++up > down)
                break;
            //2.1向下移动
            for(int i = up; i <= down; i++){
                res[i][right] = a++;
            }
            //2.2重新定义右边界,同上
            if(--right < left)
                break;
            //3.1向左移动
            for(int j = right; j >= left; j--){
                res[down][j] = a++;
            }
            //3.2重新定义下边界,同上
            if(--down < up)
                break;
            //4.1向上移动
            for(int i = down; i >= up; i--){
                res[i][left] = a++;
            }
            //4.2重新定义左边界,同上
            if(++left > right)
                break;
        }
        return res;
    }
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值