977.有序数组的平方
起初受到27.移除元素这题的影响,我以为还可以在原数组上操作,这样就不需空间复杂度了,但尝试了一番之后发现还是需要一个长度与给定数组相当的新数组来存储平方后的元素,因为可能有负数的存在,这题需要数组头尾有两个指针,比较两个指针所指元素平方后的大小并把它们平方后较大的元素加入到新数组的末尾,同时移动被取元素的指针
int* sortedSquares(int* nums, int numsSize, int* returnSize) {
*returnSize=numsSize;
int left=0;
int right=numsSize-1;
int leftVal=0;
int rightVal=0;
int ansIndex=numsSize-1;
int *ans=(int*) malloc(sizeof(int)*numsSize);
while (left<=right){
leftVal=nums[left]*nums[left];
rightVal=nums[right]*nums[right];
if(leftVal>=rightVal){
ans[ansIndex--]=leftVal;
left++;
} else{
ans[ansIndex--]=rightVal;
right--;
}
}
return ans;
}
209.长度最小的子数组
二刷滑动窗口,上一次是在七月份的时候,对思路已经有了大概的把握,就是想象有一个窗口在数组上收集各数的和,分别有左边界begin和右边界end,end-begin+1决定了窗口的大小,如果用暴力法是两层for循环,找到所有
sum>=target
的数组,但是这种方法需要O(n^2)的时间复杂度,而滑动窗口的思想则是用一个for循环去做两个for循环要做的事情
int minVal(int a, int b) {
if(a >= b)return b;
else return a;
}
int minSubArrayLen(int target, vector<int>& nums) {
int end = 0;
int begin = 0;
int min = INT_MAX;
int sum = 0;
int numSize = nums.size();
for ( end; end < numSize; end++)
//for循环的参数是右边界end,也就是每次都是end先移动然后达到target后begin跟上
{
sum += nums[end];
while (sum >= target) {
//第一想法这里是if,但是如果单独一个元素就>=target的话,就会计算错区间长度
//需要让所有满足条件的区间都显现出来才能继续移动end
min = minVal((end - begin+1),min);
sum-=nums[begin++];
}
}
if (min == INT_MAX)return 0;
return min;
}
59.螺旋矩阵II
二刷也感觉这种模拟题有无从下手的感觉,这题的思路就是模拟转圈,每转一圈都分别赋上方行,右方列,下方行,左方列这四个部分的值,一圈转完以后再进内圈,一共需要转n/2圈
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>>res(n, vector<int>(n,0));
int startx = 0;//每次开始转圈的横坐标
int starty = 0;//每次开始转圈的纵坐标
int count = 1;//从1开始到n^2结束
int offset = 1;//控制进入内圈
int loop = n / 2;
while (loop--)
{
for (int j = starty; j < n-offset; j++)//上方行
{
res[startx][j] = count++;
}
for (int i = startx; i < n - offset; i++)//右方列
{
res[i][n-offset] = count++;
}
for (int j = n - offset; j > starty; j--)//下方行
{
res[n - offset][j] = count++;
}
for (int i = n - offset; i > startx; i--)//左方列
{
res[i][starty] = count++;
}
startx++;
starty++;
offset++;
}
if (n % 2 == 1)res[startx][starty] = count;//如果n是奇数那么转到最后圈中心会缺少一个元素
return res;
}
};
又去刷相关题目的时候被卡住了,因为carl哥的教的螺旋矩阵的方法适合于方阵,还需要分奇偶性讨论,但是遇到m*n的矩阵的时候就没法轻易看出来会转多少圈,学习了一下leetcode上大神的通法就是:
设立四个边界t(top),r(right),b(bottom),l(left)遍历时用上右下左的顺利遍历,每次遍历完之后移动相应的边界,这样就避免了重复遍历
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n, vector<int>(n, 0));
int top, right, bottom, left;
top = 0;
right = n - 1;
bottom = n - 1;
left = 0;
int count = 1;
while (true)
//循环的终止条件就是边界不符合定义时
//即左边界跑到了右边界的右边
//或者下边界跑到了上边界的上边
{
for (int i = left; i <= right; i++) {
res[top][i] = count++;
}
if (++top > bottom)break;
//遍历完上面的那一行后top随即下移
//这样右边那一列的遍历就会从前一行最后一个元素的下面开始,避免重复
for (int i = top; i <= bottom; i++) {
res[i][right] = count++;
}
if (--right < left)break;
for (int i = right; i >= left; i--) {
res[bottom][i] = count++;
}
if (--bottom < top)break;
for (int i = bottom; i >= top; i--) {
res[i][left] = count++;
}
if (++left > right)break;
}
return res;
}
};