977.有序数组的平方
题目链接:有序数组的平方
视频讲解:双指针法经典题目
双指针法
此题采用一前一后的双指针,由于存在负数平方后最大的数肯定在数组两边,用前后双指针取值,i 指向数组起始位置,j 指向数组终止位置,判断两个位置平方后的值,大的放入新的数组中。这题是升序排列,要从后往前在数组中放值。
while语句判断要加上 i = j 的情况,保证取到中间的数。
做题出现的错误:
声明一个vecoter容器只是默认初始化vector<int> v;此时是个空容器,不能直接通过索引的方式对指定位置的元素进行赋值。
应该指定值初始化:vector<int> v(nums.size(), 0);
//时间复杂度:O(n)
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
vector<int> v(nums.size(), 0); // 放平方之后的新数组
int i = 0, j = nums.size() - 1;
int k = nums.size() - 1;
while(i <= j)
{
if (nums[i] * nums[i] > nums[j] * nums[j])
{
v[k--] = nums[i] * nums[i];
i++;
}
else
{
v[k--] = nums[j] * nums[j];
j--;
}
}
return v;
}
};
209.长度最小的子数
题目链接:长度最小子数组
视频讲解:拿下滑动窗口!
暴力解法
//时间复杂度:O(n^2)
//空间复杂度:O(1)
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int result = INT32_MAX; //长度结果 INT32_MAX是<limits>中定义的的常量表示int类型最大可能的值
int sum = 0; //子数组的和
int size = nums.size();
int len = 0; //子数组的长度
for (int i = 0; i < size; i++)
{
sum = 0; //这里要更新一下sum,不然会越加越大
for (int j = i; j < size; j++)
{
sum += nums[j];
if (sum >= target)
{
len = j - i + 1;
result = result < len ? result : len;
break; //满足if的条件才break出for循环
}
}
}
return result == INT32_MAX ? 0 : result; //如果result没有更新,表示不存在符合条件的子数组
}
};
滑动窗口
滑动窗口就是不断调整子序列的起始位置和终止位置,从而得出想要的结果。
暴力解法使用了两个for循环,而滑动窗口只需一个for循环,所以采用滑动窗口for循环表示的位置至关重要,如果表示起始位置,那么终止位置还是需要移动则与暴力解法无异。所以我们要用for来滑动终止的位置。
对于本题,终止位置通过for循环来移动,起始位置则通过求和后满足条件的sum减去起始位置的值实现起始位置后移动(sum = sum - nums[i];)。
判断sum与目标值时,用的是while语句,因为如果满足sum >= target,起始位置会后移动一位,移动后还是满足条件则需要继续后移动,while能保证该过程的持续性,用if的话就只能判断一次。
做题时出现的错误:
sum += nums[j];写在了while里面;
学会用三目运算符;有时可以替代min、max函数;
//时间复杂度:O(n)
//空间复杂度:O(1)
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int result = INT32_MAX; // 最后输出子数组的长度
int sum = 0; // 子数组元素的和
int len = 0; // 子数组的长度
int i = 0; // 起始的位置(前面的指针)
for (int j = 0; j < nums.size(); j++)
{
sum += nums[j];
while(sum >= target)
{
len = j - i + 1;
result = result < len ? result : len;
sum = sum - nums[i];
i++;
}
}
return result == INT32_MAX ? 0 : result;
}
};
59.螺旋矩阵II
题目链接:螺旋矩阵II
视频讲解:一入循环深似海
本题就是遵循一个循环不变量yuanze,在循环时要保证遍历同一圈的每条边元素是一样的,才不容易搞混,每条边坚持左闭右开,或者左开右闭的原则。
用vector定义二维数组:
vector<vector <int>> res(n, vector<int>(n, 0));
明白循环后 i ,j 的值是多少
//时间复杂度:O(n^2)
//空间复杂度:O(1)
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 offset = 1; // 保持左闭右开区间,遍历每行或每列时不包括最后一个元素
int count = 1; //给每个空格赋值
int loop = n / 2; //循环的次数
int mid = n / 2;
int i, j;
while (loop --)
{
i = startx;
j = starty; //写在while里面保持更新
for (j = starty; j < n - offset; j++)
{
res[startx][j] = count++;
} //for循环结束 j 的值是 n - offset
for (i = startx; i < n - offset; i++)
{
res[i][j] = count++; //此时j已经更新到了n - offset
}
for (; j > starty; j--) //j = n - offset
{
res[i][j] = count++;//此时i已经更新到了n - offset
}
for (; i > startx; i--)
{
res[i][j] = count++;
}
// 转完一圈
startx++;
starty++; // 起始位置加1(圈变小了)开始第二圈
offset++; // 圈变小截止位置多减1(右边界收缩一位)
}
// 判断n为奇数,矩阵中间还有一个值需加入
if (n % 2)
{
res[mid][mid] = count;
}
return res;
}
};