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

有序数组的平方

1.思路:

遍历整个数组将其平方,用冒泡排序将其排列。
超时!!!
应用双指针法,数组是有序的,只不过负数平方之后可能成为最大数了。
那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。
i指向开头,j指向结尾。
将较大值插入到新数组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int i = 0;
int j = nums.size() - 1;
vector<int> result(nums.size(), 0);
int n = j;
while (i<=j) {
if (nums[i] * nums[i] < nums[j] * nums[j]) {
result[n] = nums[j] * nums[j];
n--; j--;
}
else {
result[n] = nums[i] * nums[i];
n--; i++;
}
}
return result;
}
};

2.错因:注意i<=j,处理最后一个元素,else中要包含相等的元素,处理最后一个元素。

长度最小的子数组

1.思路:

没思路。。。

1.1应用2个for循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int result=INT32_MAX;
int n;
for (int i = 0; i < nums.size(); i++) {
int sum = 0;
for (int j = i; j < nums.size(); j++) {
sum += nums[j];
if (sum >= target) {
n = j - i + 1;
result = result < n ? result : n;
}
}
}
if (result == INT32_MAX) {
return 0;
}
else
return result;
}
};

显然超时。

1.2应用一个for循环

滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n^2)暴力解法降为O(n)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int sum = 0;
int result = INT32_MAX;
int i = 0;
for (int j = 0; j < nums.size(); j++) {
sum += nums[j];
while (sum >= target) {
int n = j - i + 1;
result = result < n?result:n;
sum -= nums[i++];
}
}
if (result == INT32_MAX) {
return 0;
}
else
return result;
}
};

关键在于

1
2
3
4
5
while (sum >= target) {
int n = j - i + 1;
result = result < n?result:n;
sum -= nums[i++];
}

螺旋矩阵

1.思路:

在pta上做过类似题目。
先从左到右,再从上到下,在从右到左,最后在从下到上,注意循环判断条件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n, vector<int>(n, 0));//使用vector定义一个二维数组
int startx = 0, starty = 0;//定义每循环一圈起始位置
int loop = n / 2; //每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理
int count = 1;//赋值
int offset = 1; //需要控制每一条边遍历的长度,每次循环右边界收缩一位
int i, j;
while (loop--) {
for (j = starty; j < n-offset; j++) {
res[startx][j] = count++;
}
for (i = startx; i < n - offset; i++) {
res[i][j] = count++;
}
for (; j > starty; j--) {
res[i][j] = count++;
}
for (; i > startx; i--) {
res[i][j] = count++;
}
startx++; starty++; offset++;
}
int mid = n / 2;
if (n % 2 == 1) {
res[mid][mid] = count;
}
return res;
}
};

注意都需要什么条件。