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

977.有序数组的平方

思路:序列为非递减(递增)序列,按平方值递增排序,数组两头一定是最大和第二大的。

法一(暴力解):对数组遍历平方,再进行递增排序。时间复杂度最坏O(n^2)

法二:可以利用双指针法,数组特性最大第二大分别在数组两头,head指数组头,tail指数组尾,两两分别比较,大的值进行平方放尾部,小的放回头部,tail指针逐步往前遍历。该法更类似于交换排序,时间复杂度O(n),空间复杂度(1)

vector sortedSquares(vector& nums) {
        int head = 0;
        int tail = nums.size()-1;
        for(int i = 0;i < nums.size();i++){
            if(nums[head] < 0 || nums[tail] < 0){//两者都取绝对值再比较
                nums[head] = abs(nums[head]);
                nums[tail] = abs(nums[tail]);
            }
            if(nums[tail] >= nums[head]){//更大的值放尾部再平方
                nums[tail--] *= nums[tail];
            }
            else{
                int h = nums[tail];//若前者更大,把后者放前面,前面的值平方放尾部
                nums[tail--] = nums[head]*nums[head];
                nums[head] = h;
            }
        }
        return nums;
    }

209.长度最小子数组

法一(暴力解):外层for循环控制头指针,内层for循环控制尾指针,每次外层循环一次,内层尾指针循环至尾部.枚举出所有结果,记录最小数组长度.时间复杂度O(n^2).

法二:双指针法(形象理解为滑动窗口),窗口内的元素和必须满足目标值,这是一个重要条件,然后根据窗口内的值进行窗口缩放。

思路:设置头尾指针为0,第一步,尾指针控制后窗口往后移动直至找到第一个符合条件的子集合,第二步,先记录窗口长度,然后尝试缩小前窗口(前指针),若窗口内的和符合条件则继续循环执行第二步,直到不符合条件值,则执行第一步,直到数组尾部。

时间复杂度O(n)

int minSubArrayLen(int target, vector& nums) {
        int result = INT32_MAX;//设置一个最大值,result记录最小窗口长度
        int sum = 0;//记录窗口内的所有元素的和
        int targetLength = 0;//记录当前窗口长度
        int head = 0;
        for(int tail = 0;tail < nums.size(); tail++){
            sum += nums[tail];
            while(target <= sum){//注1
                targetLength = (tail - head + 1);//记录目前满足条件子集合的长度
                if(targetLength < result){
                    result = targetLength;
                }
                sum -= nums[head++];//缩小窗口还需要把前一个元素减去再缩小
            }
        }
        return result == INT32_MAX ? 0:result;//注2
    }

本题还需要注意两个细节,注1能否把target <= sum改成target

59.螺旋矩阵||

重点是要遵循循环不变量原则,即每次处理的边的规则都需相同,下面代码遵循左闭右开原则.

1 1 2
4 5 2
4 3 3

1,2,3,4分别表示每条边的处理顺序和处理的格数

1 1 1 2
4 5 6 2
4 8 7 2
4 3 3 3

如上图每次处理包含头节点但不包含尾节点,并且如果循环圈数只有一圈,则中间元素需要单独处理

    vector> generateMatrix(int n) {
        vector> res(n, vector(n, 0));
        int startx = 0,starty = 0;//定义每一圈的起始位置
        int loop = n/2;//循环圈数
        int mid = n/2;//若圈数为奇数,则需要单独给矩阵中间赋值
        int count = 1;//从1~n方赋值
        int offset = 1;//控制每条边的长度
        int i,j;
        while(loop--){
            i = startx;
            j = starty;
            //上行从左到右,行不动,列动
            for(j = starty;j < starty + n - offset;j++){
                res[startx][j] = count++;
            }
            //右列从上到下,列不动,行动
            for(i = startx;i < startx + n - offset;i++){
                res[i][j] = count++;
            }
            //下行从右到左
            for(;j > starty;j--){
                res[i][j] = count++;
            }
            //左列从下到上
            for(;i > startx;i--){
                res[i][j] = count++;
            }
            //第二圈开始起始位置+1
            startx++;
            starty++;
            offset += 2;//相应的边界点也该往里面移动
        }
        if(n % 2){
            res[mid][mid] = count;
        }
        return res;
    }

空间复杂度为O(1),因为返回数组是题目给定的,没有所用的额外空间

你可能感兴趣的:(算法,数据结构)