977-有序数组的平方
题目链接:有序数组的平方
思路: 有序数组 --> 平方的最大在两端 --> 双向指针找到绝对值最大的
算法描述:首尾指针指向数组的两端,每次判断绝对值较大的一个,求取绝对值后存在新数组的最后。停止条件为左右指针相遇。
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int left = 0;
int right = nums.size() - 1;
vector<int> result(nums.size());
while(left <= right){
for(int i = nums.size() - 1; i >= 0; i--){
if((nums[left] + nums[right]) <= 0){
result[i] = pow(nums[left] , 2);
left++;
}
else{
result[i] = pow(nums[right] , 2);
right--;
}
}
}
return result;
}
};
时间复杂度:O(n)
209-长度最小的子数组
题目链接:长度最小的子数组
1.滑动窗口
思路:题目中要求求解连续的数组长度,对于连续这个概念自然而然地想到了可以用前后指针表示数组的范围,即双指针法。
算法描述:前后指针开始时都指向数组的起始位置,后指针开始向后移动,每次向后移动都判断当前范围之和是否满足target的大小,若满足,后指针停止移动,前指针开始向后移动,每次移动依然判断当前的前后指针指向的范围之和是否满足要求,满足则前指针继续前移,否则前指针停止,后指针开始移动。记录所有满足要求的数组范围长度,最小的即为题目所求。
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
// 滑动窗口
int i = 0; // 滑动窗口的起始位置
int sum = 0;
int len = 0;
int result = INT32_MAX;
for(int j = 0; j < nums.size(); j++){
sum += nums[j];
len++;
while(sum >= target){
len = j - i + 1; // 当前滑动窗口的大小
result = result < len ? result : len;
sum -= nums[i];
i++;
}
}
return result == INT32_MAX ? 0 : result;
}
};
算法到代码转换中的问题:
- while中的判断顺序: 进入当前while则说明当前区间满足要求 --> 记录当前区间并判断是否为最短(第15-16行)。记录后开始尝试进一步减少区间长度后是否仍满足要求,即前指针向后移动(第17-18行代码),若满足 -->进入下一次while后记录区间长度,否则进入下一次for循环即后指针向后移动。
- return处的判断:若return一直未被修改,则说明从未进入过while中,即不存在满足条件的子数组,返回0。
时间复杂度:只有一个for循环,表示子数组的结束位置,该指针遍历数组 --> O(n)
2.暴力解法
算法描述:前后指针分别代表子数组的开始和结束位置,对于每一个前指针,后指针都从前指针的位置遍历到数组结束。前指针即子数组开始的位置也可以为数组的开始至结束的位置。--> 时间复杂度:
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
// 暴力解法
int n = nums.size();
int len = 0;
int sum;
int result = INT32_MAX;
for(int i = 0; i < n; i++){
sum = 0;
for(int j = i; j < n; j++){
sum += nums[j];
if(sum >= target){
len = j - i + 1;
result = result < len ? result : len;
break;
}
}
}
return result == INT32_MAX ? 0 : result;
}
};
算法到代码转换中的问题:
- 第11行:外层循环表示从i的位置开始累加子数组,因此每一次进入i的循环时,记得将sum重新赋值为0。
- 第17行:若进入了if判断,则说明以当前i为起始位置时,累加的结果到j处就满足条件了,因此break,不必要继续累加j之后的数组元素。
时间复杂度:
59-螺旋矩阵
题目链接:螺旋矩阵
试图寻找一些打印的规律,但没有观察和总结出来,看了代码随想录的视频,讲的很清晰。附上链接:一入循环深似海 | LeetCode:59.螺旋矩阵II
算法思路:以一圈为一个循环填入数据。对于每一圈的填入,都有 左到右、上到下、右到左、下到上四个方向。问题的关键在于四个方向的数据填入边界,以及每一圈写入位置该如何表示。
结合代码描述:
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> matrix(n, vector<int>(n, 0));
int circles = 1; // 遍历的圈数
int startx = 0, starty = 0; // 定义每一圈的起始坐标
int count = 1; // 记录当前存储的元素
int i,j;
while(circles <= n/2){
i = startx;
j = starty;
for(j = starty; j < n-circles; j++){
matrix[startx][j] = count;
count++;
}
for(i = startx; i < n-circles; i++){
matrix[i][j] = count;
count++;
}
for(; j > starty; j--){
matrix[i][j] = count;
count++;
}
for(; i > startx; i--){
matrix[i][j] = count;
count++;
}
startx++;
starty++;
circles++;
}
if(n % 2 == 1)
matrix[n/2][n/2] = count;
return matrix;
}
};
1. 如何确定循环次数?
- 即需要绕多少个圈的问题。n表示矩阵的宽度,每绕一圈,在一个宽度上填入两个数,因此需要绕 n/2圈,而n为奇数时,中心只剩一个数未填,不需要再绕一个圈来填入数据,因此单独判断后填入数据即可。
2. 每一圈数据填入的位置如何确定?
- 确定每一圈的起始位置和每一个方向填入数据的终止位置(即每一个for循环中,i和j应该小于什么)。
起始位置:每绕一圈后,起始位置的x和y坐标均+1
终止位置:仅仅看每一层循环从左到右这一次数据的填入。第一层循环的终止位置为 第一行的n-1(计算机中数组下标从0开始,所以要减一),第二层循环的终止位置为第二行的n-2,第三层循环的终止位置为第三行的n-3,...第n行...因此结束位置可以使用 n- circles(当前循环的层数)来表示。
3.每一圈中坐标的具体变化?
- 从左到右: 行坐标不变,列坐标不断增加,根据初始的startx和starty写入matrix[startx][j],(其中j的变化范围为starty增长到n-circles)
- 从上到下:因为在从左到右的变化中,j坐标已经变化到相应的列上,因为数据的写入表示为matrix[i][j](其中i是变化的,从初始的startx增长到n-circles)
-从右到左:同样的在从上到下的变化中,i坐标已经变化到了相应的行上,此时数据的写入表示为matrix[i][j](其中j是变化的,变化的范围为从左到右的那一次写入的终止位置n-circles减少到最一开始的起始位置starty)
-从下到上:同样的在从右到左的变化中,j坐标已经变化到了相应的列上,此时数据的写入表示为matrix[i][j](其中i是变化的,变化的范围为从上到下的那一次写入的终止位置n-circles减少到最一开始的起始位置startx)
4.边界问题
- 对于每一圈循环的一个角(以右上角为例),既可以在从左到右的写入过程中填入数据,也可以在从上到下的过程中填入数据,因此一定要在左到右、上到下、右到左、下到上的过程中确定好边界,确保每一个角只填入数据一次。