代码随想录算法训练营第二天| 977. 有序数组的平方、209. 长度最小的子数组、59.螺旋矩阵 II
LeetCode 977题 有序数组的平方
题目链接: 977.有序数组的平方
思路:首先想到的暴力法,先平方然后排序
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
for (int i = 0; i < nums.size(); i++) {
nums[i] *= nums[i];
}
sort(nums.begin(), nums.end());
return nums;
}
};
注:该算法复杂度为O(n+nlogn)
双指针法
思路:该数组本为非递减有序数组,各元素平方后可能会出现负数平方比数组右边元素大的情况
即数组平方的最大值就在数组两端,非左即右,此时可以考虑双指针法
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
vector<int> result(nums.size(), 0); //创建一个与nums大小相同全为0的变长数组
int k = nums.size() - 1; //对新数组从后往前从大到小插入元素
for (int left = 0, right = nums.size()-1; left <= right;) {
if (nums[left] * nums[left] > nums[right] * nums[right]) {
result[k--] = nums[left] * nums[left];
left++;
}
else {
result[k--] = nums[right] * nums[right];
right--;
}
}
return result;
}
};
此解法复杂度为O(n)。
LeetCode 209题 长度最小的子数组
题目链接: 209.长度最小的子数组
思路:该题第一想法可用暴力解法,使用两个for循环,一个for用于遍历,一个用于数组元素累加直到≥目标值
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
int result = INT32_MAX; //定义最终结果,初值设置为最大值
int subLength = 0; //定义子序列长度
for (unsigned int i = 0; i < nums.size() - 1; i++) {
int sum = 0; //定义连续数组的和
for (unsigned int j = i; j < nums.size(); j++) {
sum += nums[j]; //将数组累加
if (sum >= s) { //一旦累和的值大于s
subLength = j - i + 1; //得到子序列长度
result = result < subLength ? result : subLength;
break;
}
}
}
return result == INT32_MAX ? 0 : result;
}
};
注:此解法算法复杂度为O(n^2)。
滑动窗口法
思路:不断调节子序列的起始位置和终止位置,最终得到结果
滑动窗口代码精髓
while (sum >= s) {
subLength = j - i + 1; //得到子序列的长度
result = result < subLength ? result : subLength;
sum -= nums[i++]; //不断变更i(子数组的起始位置)
}
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
int result = INT32_MAX;
int subLength = 0; //滑动窗口长度
int sum = 0; //滑动窗口之和
int i = 0; //滑动窗口起始位置
for (int j = 0; j < nums.size(); j++) {
sum += nums[j];
while (sum >= s) {
subLength = j - i + 1;
result = result < subLength ? result : subLength;
sum -= nums[i++];
}
}
return result == INT32_MAX ? 0 : result;
}
};
注:此方法时间复杂度为O(n)
LeetCode 59题 螺旋矩阵 II
题目链接: 35.螺旋矩阵 II
思路:循环不变量!!!
模拟顺时针方向画矩阵
1.从左到右填充上行
2.从上到下填充右列
3.从右到左填充下行
4.从下到上填充左列
注:要坚持循环不变量原则(本题设置为左闭右开区间)
class Solution {
public:
vector<vector<int> > generateMatrix(int n) {
vector<vector<int> > res(n, vector<int>(n, 0));
int startx = 0, starty = 0; //定义每循环一个圈的起始位置
int loop = n / 2; //每个圈循环几次
int mid = n / 2; //矩阵中间的位置
int count = 1; //用来给矩阵中每一个空格赋值
int offset = 1; //每一圈循环都需要控制每一条边遍历的长度
int i, j;
while (loop--) {
i = startx;
j = starty;
//下面4个for模拟旋转一圈
//模拟填充上行从左到右
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用于控制每一圈中每一条边遍历的长度
offset += 2;
}
//如果n为奇数,则需要单独给矩阵最中间的位置赋值
if (n % 2) {
res[mid][mid] = count;
}
return res;
}
};