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

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

一 、有序数组的平方

977.有序数组的平方
提示:

1 <= target <= 109
1 <= nums.length <= 105
1 <= nums[i] <= 105

算法

1) 暴力求解

   就是先遍历数组 ,每一个数平方后,调用STL的sort函数(快速排序)进行排序,复杂度就是 O ( n + l o g n ) O(n + logn) O(n+logn)

2) 双指针法

   由于数组本身就是有序的,如果数组都是正数,平方后,相对位置是不会发生变化的,不过存在负数后就可能交换位置。但是无论正数还是负数,平方后,最大值就在数组的两端,不可能在中间。使用想到使用双指针,一个指向最前面,一个指向最后面。再申请一个额外数组 v e c t o r < vector< vector<int > r e s u l t ( k + 1 , 0 ) > result(k + 1, 0) >result(k+1,0)。每一次进行平方后的数的比较,数大的将其放到 r e s u l t result result当中(从后往前放)指针向前(后)移动。另一个不变。直到两个指针相遇,算法结束。
   易知其时间复杂度为 O ( n ) O(n) O(n),空间复杂度也是 O ( n ) O(n) O(n)

源码

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

            }
        }

        return result;

    }
};

二.长度最小的子数组

209长度最小的子数组

提示:

1 <= target <= 109
1 <= nums.length <= 105
1 <= nums[i] <= 105

算法

滑动窗口

滑动窗口介绍:

   所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。在暴力解法中,是一个for循环滑动窗口的起始位置,一个for循环为滑动窗口的终止位置,用两个for循环 完成了一个不断搜索区间的过程。
   窗口内是什么?
   如何移动窗口的起始位置?
   如何移动窗口的结束位置?
1、窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。
2、窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)。
3、窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。

   在这道题目当中,w是作为当前滑动窗口的大小,会动态更新, l , r l, r l,r是滑动窗口的左右边界。
   在开始时,左边界不动,右边界先动。(1)在右边界向右移动的过程当中,窗口内的总和 s u m sum sum会不断增加 n u m s [ i ] nums[i] nums[i].
   当 s u m sum sum大于目标 s s s后,右边界不动,左边界开始向右移动,同时窗口内总和 s u m sum sum减小 n u m s [ l ] nums[l] nums[l],在不断的移动过程中,会在满足条件时,进行窗口大小的比较。
注意途中左边界不可以超过右边界

源码


class Solution {
public:
	int minSubArrayLen(int s, vector<int>& nums) {
		int result = INT32_MAX;
		int sum = 0;  //滑动窗口之和
		int l = 0;
		int	r = -1;  //注意从 -1开始   一开始调试代码就是这里  出问题  r=0 开始
		int w = 0; //滑动窗口的宽度
		int sublength = INT32_MAX;
		for (int i = 0; i < nums.size(); i++) {
			sum += nums[i];  //未满足要求 就动右边界。
			r++;   
			while (sum >= s && r>= l) {  //满足条件  就动左边界。
				w = r - l + 1;
				sublength = sublength <= w ? sublength : w;
				sum -= nums[l++];
			}
		}
		return sublength == INT32_MAX ? 0 : sublength;
	}
};
复杂度分析

   显然算法时间复杂度为 O ( n ) O(n) O(n),空间复杂度为$O(1)。

提示:

1 <= n <= 20

三、 螺旋矩阵 ||

59. 螺旋矩阵 II

算法

1)基本思想

   这里我借用了螺旋打印矩阵的思想,不过这里变成了对方阵进行赋值。也就是按照遍历的顺序进行从 1 到 n 2 n^2 n2进行赋值。

   由于一个矩阵可以由它的最左上角以及最右下角唯一确定。不妨设最左上角为 A ( t R , t C ) A(tR,tC) A(tR,tC),最右下角 B ( d R , d C ) B(dR,dC) B(dR,dC)。而螺旋打印(赋值)矩阵无非就是每一次打印(赋值)以 A , B A,B A,B唯一确定的矩阵。每一次打印(赋值)结束后, A A A向下, B B B向上。也就是:
          t R + + , t C + + , d R − − , d C − − tR++, tC++, dR--, dC-- tR++,tC++,dR,dC

   当 A , B A,B A,B错开后,算法结束:

          t R < = d R & & t C < = d C tR <= dR \&\& tC <= dC tR<=dR&&tC<=dC

2)打印(赋值)

   对以 A , B A,B A,B唯一确定的矩阵而言,可以有三种情况:
   (1)列向量。此时需要一个 f o r for for循环,从上到下遍历即可。

   (2)行向量。此时需要一个 f o r for for循环,从左到右遍历即可。

   (3)一般方阵。就需要四个 w h i l e while while循环。
3.1 先向右打印(赋值)。同一行上遍历列。
3.2 再向下打印(赋值)。同一列上遍历行。
3.3 再向左打印(赋值)。同一行上遍历列。
3.4 最后向上打印(赋值)。同一列上遍历行。

源码

class Solution {
public:
    
    vector<vector<int>> generateMatrix(int n) {
        int tR = 0;
        int tC = 0;
        int dR = n - 1;
        int dC = n - 1;
        vector<vector<int>> matrix(n, vector<int>(n));
        while (tR <= dR && tC <= dC) {

            printEdge(matrix, tR++, tC++, dR--, dC--);
        }
  
        return matrix;
    }

     void printEdge(vector<vector<int>>& m, int tR, int tC, int dR, int dC) {
        if (tR == dR) {
            for (int i = tC; i <= dC; i++) {
                m[tR][i] = base++;
            }
        }
        else if (tC == dC) {
            for (int i = tR; i <= dR; i++) {
                m[i][tC] = base++;
            }
        }
        else {
            int curC = tC;
            int curR = tR;
            while (curC != dC) {
                m[tR][curC] = base++;
                curC++;
            }
            while (curR != dR) {
                m[curR][dC] = base++;
                curR++;
            }
            while (curC != tC) {
                m[dR][curC] = base++;
                curC--;
            }
            while (curR != tR) {
                m[curR][tC] = base++;
                curR--;
            }
        }
    }
private:
    int base = 1;
};
public class leetcode59 {
    public static int base =1;
    public static int[][] generateMatrix(int n) {
        int tR = 0;
        int tC = 0;
        int dR = n-1;
        int dC = n-1;
        int[][] matrix=new int[n][n];
        while (tR <= dR && tC <= dC) {
            printEdge(matrix, tR++, tC++, dR--, dC--);
        }
        return matrix;
    }
    public static void printEdge(int[][] m, int tR, int tC, int dR, int dC) {
        if (tR == dR) {
            for (int i = tC; i <= dC; i++) {
                m[tR][i] =base++;
            }
        } else if (tC == dC) {
            for (int i = tR; i <= dR; i++) {
                m[i][tC] =base++;
            }
        } else {
            int curC = tC;
            int curR = tR;
            while (curC != dC) {
                m[tR][curC]  =base++;
                curC++;
            }
            while (curR != dR) {
                m[curR][dC]  =base++;
                curR++;
            }
            while (curC != tC) {
                m[dR][curC]  =base++;
                curC--;
            }
            while (curR != tR) {
                m[curR][tC]  =base++;
                curR--;
            }
        }
    }
}

复杂度分析

    时间复杂度 O ( n 2 ) O(n^2) O(n2) ,遍历二维矩阵的时间
    空间复杂度 O ( 1 ) O(1) O(1) , 没有使用额外数据结构

java提交问题分析

   在使用java语言时。我使用idea编写并且执行结果正确,同样在leetcode控制台输出正确,但提交后结果就出错了。但用c++使用同样逻辑编写却成功提交了。后来,在群里请教后,发现,由于我定义了 public static int base =1;而因为力扣测试用例的机制,如果你在solution外面定义了变量使用,是不会清空的。可能导致在多次进行代码执行的时候,我的base每一次的执行会一直更新,不会重新变成1. 不过单次执行时可以通过。

  • 20
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值