文章目录
代码随想录算法训练营第二天 | 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;
}
};
二.长度最小的子数组
提示:
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
三、 螺旋矩阵 ||
算法
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. 不过单次执行时可以通过。