977.有序数组的平方
题目建议: 本题关键在于理解双指针思想
题目链接:. - 力扣(LeetCode)
文章讲解:代码随想录
视频讲解: 双指针法经典题目 | LeetCode:977.有序数组的平方_哔哩哔哩_bilibili
题目:给你一个按 非递减顺序 排序的整数数组 nums
,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
示例 1:
输入:nums = [-4,-1,0,3,10] 输出:[0,1,9,16,100] 解释:平方后,数组变为 [16,1,0,9,100] 排序后,数组变为 [0,1,9,16,100]
示例 2:
输入:nums = [-7,-3,2,3,11] 输出:[4,9,9,49,121]
最朴实无华的做法,就是将数组内的所有元素先进行平方,然后使用sort函数将数组元素排序,但时间复杂度较大,下面使用双指针的思想来解决这道题
首先我们可以根据示例来看,不管有无负数,只要是非递减顺序,最大的平方肯定在两侧,所以我们每次只需要比较最两侧的元素的平方大小,将更大的元素平方放入另一个数组存起来;
因此,我们还需要新建一个数组res,size = nums.size()。由于最后返回的数组也要按照非递减顺序,所以我们只要将更大的元素平方放在数组res的末尾,这里使用l来记录数组res的索引,l初始化为nums.size() - 1,每存入一次,l--
如果是首位元素的平方大于末位元素的平方,即将首位元素的索引left向右移位,反过来将末位元素的索引right左移,并进行下一次比较,直到left>right, 跳出循环
具体代码如下:
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int left = 0;//left指向起始位置
int right = nums.size() - 1;//right指向终止位置
int l = nums.size() - 1;
vector<int> res(nums.size(), 0);
while(left <= right){
if (nums[left] * nums[left]>= nums[right] * nums[right]){
res[l] = nums[left] * nums[left];
left ++;
}else{
res[l] = nums[right] * nums[right];
right --;
}
l --;
}
return res;
}
};
209. 长度最小的子数组
题目:给定一个含有 n
个正整数的数组和一个正整数 target
。
找出该数组中满足其总和大于等于 target
的长度最小的
子数组
[numsl, numsl+1, ..., numsr-1, numsr]
,并返回其长度
。如果不存在符合条件的子数组,返回
0
。
示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3]
是该条件下的长度最小的子数组。
示例 2:
输入:target = 4, nums = [1,4,4] 输出:1
示例 3:
输入:target = 11, nums = [1,1,1,1,1,1,1,1] 输出:0
本题需要找到长度最小的子数组,且子数组内元素总和必须大于给定的target,设定长度为l,每次找到满足条件的子数组后,都要和之前符合条件的数组长度进行比较,取最小值。
首先,要怎么知晓子数组的长度,这里的长度与元素个数有关,因此我们可以通过首尾元素的索引相减得到子数组长度;
其次,要怎么更新子数组长度,或者说使用什么样的方法来寻找下一个符合条件的子数组。假设我们从i=0开始遍历,count+=nums[i],直到count>=target找到符合条件的子数组,记录下长度l,此时有两种选择
一种是重新从i=1开始遍历,直到找到下一个符合条件的数组,也就是暴力循环的方法
另一种是利用之前相加的结果,由于原数组为正数数组,当刚好找到符合条件的子数组时,将最前面的元素减去,同时索引右移,i++,加上i=j后的元素,进行下一轮的条件循环判断,这样就能减少计算量
最后要考虑到一种计算情况,所有元素之和都不满足条件,返回0
具体代码
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int i = 0, j = 0;
int count = 0, l = INT_MAX;
for (i = 0;i < nums.size(); i++){
count += nums[i];
while(count >= target){
l = min(i - j + 1, l);
count -= nums[j];
j++;
}
}
if (l == INT_MAX) return 0;
return l;
}
};
这里用到了滑动窗口的思想,可以理解为两个指针的移动,其中一个是不变的,另一个是变化的,当达到某个条件的时候,将不变的指针进行移动,这样窗口的长度是能够更新变化的。
59.螺旋矩阵II
给你一个正整数 n
,生成一个包含 1
到 n2
所有元素,且元素按顺时针顺序螺旋排列的 n x n
正方形矩阵 matrix
。
示例 1:
输入:n = 3 输出:[[1,2,3],[8,9,4],[7,6,5]]
示例 2:
输入:n = 1 输出:[[1]]
刚开始看这题, 有点懵,外围循环能写,但是到底要循环多少次,什么时候停止
首先,在进行循环赋值的时候,需要考虑到左右的值,可以左开右闭,也可以左闭右开,但不能搞混了,否则就会重复赋值
显然,矩阵维度是n*n,同时我们需要定义每一次循环赋值的起点,这里定义起始坐标startx=0,starty=0,然后每一层赋值后,将startx++,starty++
通过观察矩阵,可以发现n=3,只需要赋值一层,n=4时,赋值两层,n=5时,赋值两层,所以循环次数(赋值)loop=n/2,而每一条边赋值结束的条件也不同,这里定义一个变量offset = 1,来更新每条边的终止条件
最后,如果n为奇数时,需要对中心的位置单独赋值
具体代码如下:
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n, vector<int>(n, 0));
int startx = 0, starty = 0;
int i = 0, j = 0;
int loop = n / 2;
int count = 1;
int offset = 1;
while (loop --){
i = startx;
j = starty;
for (; j < n - offset; j++){
res[i][j] = count++;
}
for (; i < n - offset; i++){
res[i][j] = count++;
}
for (;j > starty; j--){
res[i][j] = count++;
}
for (;i > startx;i--){
res[i][j] = count++;
}
startx ++;
starty ++;
offset ++;
}
if (n % 2){
res[n/2][n/2] = count;
}
return res;
}
};