977.有序数组的平方
题目链接:力扣
解析:
分析题目意思我们可以发现,题目给到的是一个 具有 正负 的有序序列,题目让我们按照平方来再排序,也就是我们需要考虑正负两种情况下的平方。
因此本道题,我们采取双指针+减而治之的算法思想。绝对值最大的两个数,一定位于向量的末尾或者开头,因此每一次比较我门都能赛出平方后最大的那个数,此时必定能将问题规模减去1。
为了方便的记录平方后的结果,我在这里重新开辟了一个跟原向量一样大小的空间。
因此最后的时间复杂度与空间复杂度均为O(n)。如果你有兴趣,也可以继续尝试将此算法改造成就地算法。
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
vector<int> nums_1 = nums;
int hi = nums_1.size() - 1;
int lo = 0;
int pos = nums_1.size() - 1;
while (lo < hi){
if(abs(nums_1[lo]) < abs(nums_1[hi])){
nums[pos--] = nums_1[hi] * nums_1[hi];
hi--;
}
else{
nums[pos--] = nums_1[lo] * nums_1[lo];
lo++;
}
}
nums[pos] = nums_1[lo] * nums_1[lo]; //lo hi相会 记录最后一次结果,此次结果也必定是最小的
return nums;
}
};
209.长度最小的子数组
题目链接:力扣
解析:
分析题意可得,给出的向量非有序但非负,希望输出的结果是满足 >= target 的最短区间长度。如果熟悉计算机网络的同学,肯定对滑动窗口机制再为熟悉不过了,而本道题也是采用了类似的思想。
首先我们构造两个指针,首指针不动,尾指针向后移并不断累加,滑动窗口一直变大,直至找到第一个区间;记录及更新最小长度后,首指针向前移动,窗口首位置往前移动,并将移动的数值从sum中减掉。
此时分为两种情况:
- 收缩一格后,sum >= target,则此时继续更新min,首指针再向前一格,窗口向后收缩
- 收缩一格后,sum < target,则此时尾指针向后扩张,窗口向后扩张
按照此思路一直滑动窗口,若该次窗口满足,则比较且更新最短区间长度。我们可以一直移动至向量最后,此时便可得到最短区间长度。
注:最短的区间长度不会小于1,此时刚好有一个值 >= target,此时已经得到我们最想要的结果,因此直接返回即可,无需继续滑动窗口。
根据此思路,窗口的lo与hi均单向扩张,不会回溯,且无需开辟额外空间,因此时间复杂度为O(n),空间复杂度为O(1)。
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int min = 0;
int lo = 0;
int sum = 0;
int hi = lo; // 双指针 hi与 lo ,sum记录区间的总和 ,min记录最小区间长
while(hi < nums.size() && lo < nums.size()){
sum += nums[hi];
if(sum >= target){
int temp = hi - lo + 1; // 区间长度记得加一
if(min == 0){
min = temp;
}
else if(temp < min){
min = temp;
}
if(min == 1) {
return min; // 由题意可知,最短的区间就是单个值大于等于target,此时直接返回即可
}
sum -= nums[lo]; // 找到符合要求的一段区间 记录完毕min后 将区间首指针向前移位,同时sum减掉首值
sum -= nums[hi];// 减去尾值,因为再循环一次时会加回来
lo++; // 首指针减完再前移
}
else{
hi++;// 若小于目标则尾指针向后移动
}
}
return min;
}
};
59.螺旋矩阵II
题目链接:力扣
解析:
该题是一个矩阵打印的题目,主要涉及的是循环体的构造及边界条件的确定。
核心思想仍然是减治的思想,通过一圈一圈的赋值,让矩阵规模不断缩小,问题规模也随之缩小。
赋值分为四种情形:
- 上 边+ 从左至右
- 右 边+ 从上至下
- 下 边+ 从右至左
- 左 边+ 从下往上
按照此顺序,不断循环。需要注意的是,矩阵右四个角,每个角上的顶点被两条边共享,本算法将相交点均交予 下一条边处理,也就是将上一条边的末尾作为下一条边的起始。
注意:边长n为奇偶时,最后一步不一样。n为偶数时,可以通过n/2轮,对于矩阵循环顺序赋值将问题解决;而n为奇数时,会剩余中间一个格子,此时需额外赋值一次。
根据本算法,每个格子被遍历与赋值一次,总共n^2个格子,因此时间复杂度为O(n^2)【已是此类问题最好的时间复杂度了】,空间复杂度为O(1)。
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> nums(n, vector<int>(n, 0));
int start_x = 0;
int start_y = 0;//每轮起始位置
int offset = 1;//每轮结束位置向前偏移量
int round = n/2;// 逆时针循环转圈轮次
int count = 1; //矩阵赋值计数
while(round){
int i = start_x;
int j = start_y;
for(; j < n - offset; j++){ //从左至右
nums[i][j] = count++;
}
for(; i < n - offset; i++){ //从上至下
nums[i][j] = count++;
}
for(; j > start_y; j--){ //从右至左
nums[i][j] = count++;
}
for(; i > start_x; i--){ //从下至上
nums[i][j] = count++;
}
start_x++;
start_y++;
offset++; //一圈赋值结束,矩阵收缩
round--;// 轮次减1
}
if(n % 2 == 1){
nums[n/2][n/2] = n*n; //奇数情况的平方仍为奇数,意味着中间会剩余一个格子
}
return nums;
}
};