第一题
977.有序数组的平方
①暴力解法:将数组中每个元素平方后再排序;
②双指针解法:数组中有负数,所以平方后最大的数字可能出现在数组的左右两侧位置,且左右两侧数字的平方一定大于中间数字的平方。因此,我们可以设置两个指针left和right分别指向数组的首尾两侧,比较平方后较大的数字,插入新数组的末尾,然后移动指针继续比较,直到将原先数组的平方全部放入新数组中为止。
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int size = nums.size();
vector<int> res(size,0);
int i = 0, j = size - 1, k = j;
while(i <= j){
if(nums[i] * nums[i] > nums[j] * nums[j]){
res[k--] = nums[i] * nums[i];
i++;
}
else{
res[k--] = nums[j] * nums[j];
j--;
}
}
return res;
}
};
第二题
209.长度最小的子数组
①暴力解法:两次for循环,时间复杂度为O();
②滑动窗口法:一次for循环解决问题,只需对滑动窗口的右边界进行for循环,左边界则动态的更新,时间复杂度为O(n)。
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int sum = 0, res = INT_MAX;
for(int i = 0, j = 0; j < nums.size(); j++){
sum += nums[j];
while(sum >= target){
int subLength = j - i + 1;
res = min(res,subLength);
sum -= nums[i];
i++;
}
}
if(res == INT_MAX)
return 0;
return res;
}
};
第三题
59.螺旋矩阵Ⅱ
这道题通过模拟法解决,要注意判断边界问题。
模拟顺时针画矩阵的过程如下:
- 填充上行从左到右
- 填充右列从上到下
- 填充下行从右到左
- 填充左列从下到上
①循环不变量方法:每次填充相同的数量,按照左闭右开区间,即:[)的方式进行,如下图所示,每次移动相同的位置,下一个边界处本次移动不处理。还需要注意的是,当n为基数时,需要手动添加中间那个位置的元素!
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n,vector<int>(n,0));
int startx = 0, starty = 0, count = 1;
int offset = 1;
int mid = n / 2;
int time = mid;
while(time-- > 0){
int i = startx, j = starty;
for(; j < n - offset; j++){
res[i][j] = count++;
}
for(; i < n - offset; i++){
res[i][j] = count++;
}
for(; j > offset - 1; j--){
res[i][j] = count++;
}
for(; i > offset - 1; i--){
res[i][j] = count++;
}
offset++;
startx++;
starty++;
}
if(n % 2 == 1){
res[mid][mid] = count;
}
return res;
}
};
②一种更为通用的解法:来源于54题螺旋矩阵高赞题解的思路。是一种更加通用的解法,能够解决m*n这种一般矩阵的问题,不必非得是n*n矩阵。
本质思想是:每次移动后改变边界,并判断边界条件不在满足逻辑关系,不满足便跳出循环。
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n,vector<int>(n,0));
//分别定义上下左右侧的边界
int up = 0;
int down = n - 1;
int left = 0;
int right = n - 1;
//a为添加到matrix相应位置的数字
int a = 1;
while(1){
//1.1向右移动
for(int j = left; j <= right; j++){
res[up][j] = a++;
}
//1.2重新定义上边界,若上边界超出下边界,则跳出循环
if(++up > down)
break;
//2.1向下移动
for(int i = up; i <= down; i++){
res[i][right] = a++;
}
//2.2重新定义右边界,同上
if(--right < left)
break;
//3.1向左移动
for(int j = right; j >= left; j--){
res[down][j] = a++;
}
//3.2重新定义下边界,同上
if(--down < up)
break;
//4.1向上移动
for(int i = down; i >= up; i--){
res[i][left] = a++;
}
//4.2重新定义左边界,同上
if(++left > right)
break;
}
return res;
}
};