Day2 数组02
一、有序数组的平方
给你一个按 非递减顺序 排序的整数数组 nums
,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
示例 1:
输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]
示例 2:
输入:nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]
1、暴力法
- 先直接遍历数组,将数组里面的值变为平方;
- 由于有负数的存在,所以要再次进行排序;
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
//平方
for(int i = 0; i < nums.size(); i++)
{
nums[i] = nums[i]*nums[i];
}
//冒泡排序(会超时)
// for(int i = 0; i < nums.size() - 1; i++)
// {
// for(int j = 0; j < nums.size() - 1; j++)
// {
// if(nums[j] > nums[j+1]){
// int temp = nums[j];
// nums[j] = nums[j+1];
// nums[j+1] = temp;
// }
// }
// }
//快排
sort(nums.begin(), nums.end());
return nums;
}
};
2、双指针法
由于一个数组里面有正有负,但是平方过后,一定是最两边的值大于中间的值,所以可以使用双指针法
- start指向起始位置,end指向终止位置;
- 定义一个新数组result,和nums数组一样的大小,让k指向result数组终止位置;
- 比较最末和最始的位置
- 如果最始大于最末,则将最始的数值的平方添加到result数组的最末,此时
end--,k--
; - 如果最末大于最始,则将最末的数值的平方添加到result数组的最末;此时
start++,k--
;
- 如果最始大于最末,则将最始的数值的平方添加到result数组的最末,此时
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int k = nums.size() - 1;
vector<int> result(nums.size(), 0);
int start = 0;
int end = nums.size() - 1;
while(start <= end)
{
if(nums[start]*nums[start] < nums[end]*nums[end])
{
result[k] = nums[end]*nums[end];
k--;
end--;
}
else
{
result[k] = nums[start]*nums[start];
k--;
start++;
}
}
return result;
}
};
二、长度最小的子数组
给定一个含有 n
个正整数的数组和一个正整数 target
。
找出该数组中满足其总和大于等于 target
的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr]
,并返回其长度**。**如果不存在符合条件的子数组,返回 0
。
示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
示例 2:
输入:target = 4, nums = [1,4,4]
输出:1
示例 3:
输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0
1、暴力法
-
外层循环(i): 从数组的第一个元素开始,作为子序列的起始位置。
-
内层循环(j): 从起始位置(i)开始,依次累加元素,直到子序列的和大于等于目标值
s
。- 如果满足条件,记录当前子序列的长度
subLength = j - i + 1
,即起始位置到结束位置的距离加1,即子序列的长度。 - 然后将当前长度与之前最短长度
result
比较,保留较小者。 - 一旦找到了符合条件的子序列,就退出内层循环,因为我们只关心最短的子序列。
- 如果满足条件,记录当前子序列的长度
-
外层循环每次都会从下一个位置开始,继续寻找下一个符合条件的子序列,直到遍历完整个数组。
-
最终返回
result
,如果result
没有被更新过,说明没有符合条件的子序列,返回0。
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
int result = INT32_MAX; // 最终的结果
int sum = 0; // 子序列的数值之和
int subLength = 0; // 子序列的长度
for (int i = 0; i < nums.size(); i++) { // 设置子序列起点为i
sum = 0;
for (int j = i; j < nums.size(); j++) { // 设置子序列终止位置为j
sum += nums[j];
if (sum >= s) { // 一旦发现子序列和超过了s,更新result
subLength = j - i + 1; // 取子序列的长度
result = result < subLength ? result : subLength;
break; // 因为我们是找符合条件最短的子序列,所以一旦符合条件就break
}
}
}
// 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
return result == INT32_MAX ? 0 : result;
}
};
2、滑动窗口法
滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果;是维护一个窗口,窗口内的元素满足某个条件,然后不断调整窗口的位置,以找到满足条件的最短窗口。
- 开始遍历数组,不断将右边界的元素加入窗口,并维护
sum
。 - 当
sum
大于等于目标值s
时,窗口内的元素满足条件,可以考虑缩小窗口。 - 缩小窗口的过程是不断将左边界的元素从窗口中移出,同时更新
sum
,直到sum
小于目标值s
。 - 在缩小窗口的过程中,记录每次窗口大小的变化,以便最后找到最短的满足条件的子数组。
- 最终返回
minLength
,如果minLength
仍然是INT_MAX
,说明没有符合条件的子数组,返回0。
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
int left = 0; // 窗口的左边界
int sum = 0; // 窗口内元素的和
int minLength = INT_MAX; // 最小子数组长度,初始化为一个很大的值
for (int right = 0; right < nums.size(); ++right) {
sum += nums[right]; // 将右边界元素加入窗口
// 当窗口内元素的和大于等于目标值 s 时,可以考虑缩小窗口
while (sum >= s) {
minLength = min(minLength, right - left + 1); // 更新最小长度
sum -= nums[left]; // 缩小窗口,左边界向右移动
left++;
}
}
// 如果 minLength 仍然是 INT_MAX,说明没有符合条件的子数组
return (minLength == INT_MAX) ? 0 : minLength;
}
};
三、螺旋矩阵Ⅱ
给你一个正整数 n
,生成一个包含 1
到 n2
所有元素,且元素按顺时针顺序螺旋排列的 n x n
正方形矩阵 matrix
。
示例 1:
输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]
示例 2:
输入:n = 1
输出:[[1]]
- 首先创建一个大小为 n x n 的矩阵
matrix
,并将所有元素初始化为0。 - 定义四个变量
top
,bottom
,left
,right
来表示当前螺旋矩阵的边界。它们的初始值分别是矩阵的上、下、左、右边界。top
初始值为 0,表示矩阵的上边界在第 0 行。bottom
初始值为n - 1
,表示矩阵的下边界在第n - 1
行。left
初始值为 0,表示矩阵的左边界在第 0 列。right
初始值为n - 1
,表示矩阵的右边界在第n - 1
列。
- 使用
num
来表示当前要填充的数字,从1开始递增。 - 进入一个循环,直到填充完所有的数字。在每一轮循环中,我们按照顺时针的顺序填充当前边界。
- 首先从左到右填充上边界,然后从上到下填充右边界,接着从右到左填充下边界,最后从下到上填充左边界。
- 在每次填充边界时,我们将
num
的值赋给矩阵中相应位置的元素,并将num
递增。 - 同时,我们也会相应地更新当前边界的位置,以准备填充下一个边界。
- 最终,当
num
大于n * n
时,表示所有数字都已经填充完毕,我们返回生成的螺旋矩阵。
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> matrix(n, vector<int>(n, 0)); // 初始化一个 n x n 的矩阵,所有元素初始值为0
int top = 0, bottom = n - 1, left = 0, right = n - 1; // 定义四个边界
int num = 1; // 从1开始填充矩阵
while (num <= n * n) {
// 从左到右填充上边界
for (int i = left; i <= right; ++i) {
matrix[top][i] = num++;
}
++top;
// 从上到下填充右边界
for (int i = top; i <= bottom; ++i) {
matrix[i][right] = num++;
}
--right;
// 从右到左填充下边界
for (int i = right; i >= left; --i) {
matrix[bottom][i] = num++;
}
--bottom;
// 从下到上填充左边界
for (int i = bottom; i >= top; --i) {
matrix[i][left] = num++;
}
++left;
}
return matrix;
}
};
四、总结
后面两个题目,滑动窗口以及螺旋,我刚开始完全没有思路,必须要看完讲解之后才能下手,感觉越来越难了呜呜,希望下次可以做出来更多的题目,有更多的思路;还有,问了gpt很多问题,他真好,给出的解题方法甚至更简单易懂!