977.有序数组的平方
给你一个按 非递减顺序 排序的整数数组 nums
,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]
输入:nums = [-7,-3,2,3,11] 输出:[4,9,9,49,121]
解法1:当然是暴力咯
C++版本:注意冒泡排序过不了,用快排吧
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
for(int i = 0; i<nums.size();i++){
nums[i] = nums[i]*nums[i];
}
// return maoPaoSort(nums);
sort(nums.begin(),nums.end());
return nums;
}
// vector<int> maoPaoSort(vector<int>& nums) { //冒泡排序
// for(int i = 0; i<nums.size();i++){
// for(int j = i; j<nums.size(); j++){
// if(nums[i]>nums[j]){
// int temp = 0;
// temp = nums[i];
// nums[i] = nums[j];
// nums[j] = temp;
// }
// }
// }
// return nums;
// }
};
Python版本:
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
nums = [i**2 for i in nums]
nums.sort()
return nums
解法2:双指针法
数组其实是有序的, 那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。此时可以考虑双指针法了,i指向起始位置,j指向终止位置。比较平方后的大小,存入到result中。
C++版本:
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
vector<int> result;
for(int i = 0, j = nums.size()-1; i <= j;){
if (nums[i]*nums[i] < nums[j]*nums[j]){
result.push_back(nums[j]*nums[j]);
j--;
}
else{
result.push_back(nums[i]*nums[i]);
i++;
}
}
reverse(result.begin(),result.end()); // 反转
return result;
}
};
Python版本:
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
result = []
i = 0
j = len(nums)-1
while(i<=j):
if(nums[i]**2<nums[j]**2):
result.append(nums[j]**2)
j -= 1
else:
result.append(nums[i]**2)
i += 1
result.reverse()
return result
209.长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
输入:target = 7, nums = [2,3,1,2,4,3] 输出:2 解释:子数组 [4,3]是该条件下的长度最小的子数组。
解法一:暴力解决,两层for循环,不断更新子数组的长度,写了半天,超时了。
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int result = INT32_MAX;
for(int i = 0; i<nums.size(); i++){
int subArrLength = 1;
int currentNum = nums[i];
// cout << nums[i] << endl;
if(currentNum>=target){
return 1;
}
else{
for(int j = i + 1; j<nums.size();){
subArrLength++;
currentNum = currentNum + nums[j];
// cout << nums[j] << endl;
if (currentNum<target){
j++;
}
else{
result = result<subArrLength ? result : subArrLength;
// cout <<"subArrLength"<<subArrLength <<endl;
break;
}
}
}
}
return result == INT32_MAX ? 0 : result;
}
};
解法二:滑动窗口
在本题中实现滑动窗口,主要确定如下三点:
- 窗口内是什么?
- 如何移动窗口的起始位置?
- 如何移动窗口的结束位置?
窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。
窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)。窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。
- 滑动窗口:本质是满足了单调性,即左右指针只会往一个方向走且不会回头。收缩的本质即去掉不再需要的元素。也就是做题我们可以先固定移动右指针,判断条件是否可以收缩左指针算范围。大家可以好好理解一下。
- 加入滑动窗口中有负数怎么办?
如果有负数的话感觉也不能用滑动窗口了,因为有负数的话无论你收缩还是扩张窗口,你里面的值的总和都可能增加或减少,就不像之前收缩一定变小,扩张一定变大,一切就变得不可控了。如果要 cover 所有的情况,那每次 left 都要缩到 right,那就退化为暴力了哈哈。- 在滑动窗口类型题目里有没有去DEBUG的什么小技巧呢?
一般是怀疑哪里有问题就打印哪里 像今天的滑动窗口 就可以把窗口首尾的下标变化过程打印出来 能很清楚的看到窗口是怎样移动的- 双指针和滑动窗口有什么区别,感觉双指针也是不断缩小的窗口。这道题,我想用两头取值的双指针,结果错了?
因为两头指针走完相当于最多只把整个数组遍历一遍,会漏掉很多情况。滑动窗口实际上是双层遍历的优化版本,而双指针其实只有一层遍历,只不过是从头尾开始遍历的。
滑动窗口的原理是右边先开始走,然后直到窗口内值的总和大于target,此时就开始缩圈,缩圈是为了找到最小值,只要此时总和还大于target,我就一直缩小,缩小到小于target为止在这过程中不断更新最小的长度值,然后右边继续走,如此反复,直到右边碰到边界。这样就保证了可以考虑到最小的情况
其实本题就是利用双指针来实现滑动窗口的收缩与扩张,实质还是双指针的解题思想。
C++版本:
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int result = INT32_MAX;
int i = 0;
int currentNum = 0;
int subArrLength = 0;
for(int j = 0; j<nums.size(); j++){
currentNum += nums[j];
while(currentNum >= target){ // 如多当前累加值大于目标值
subArrLength = j - i + 1; //滑动窗口的长度
result = result<subArrLength?result:subArrLength;
currentNum -= nums[i++]; //收缩窗口
}
}
return result == INT32_MAX ? 0 : result;
}
};
Python版本:
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
result = float("inf")
currentNum = 0
i = 0
subArrLength = 0
for j in range(len(nums)):
currentNum += nums[j]
while(currentNum >= target):
subArrLength = j - i + 1
result = min(subArrLength,result)
currentNum -= nums[i]
i += 1
return 0 if result == float("inf") else result
59.螺旋矩阵II
给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
示例:
输入: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]
纯纯一个模拟题。
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n, vector<int>(n, 0)); // 使用vector定义一个二维数组
int startx = 0, starty = 0; // 定义每循环一个圈的起始位置
int loop = n / 2; // 每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理
int mid = n / 2; // 矩阵中间的位置,例如:n为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2)
int count = 1; // 用来给矩阵中每一个空格赋值
int offset = 1; // 需要控制每一条边遍历的长度,每次循环右边界收缩一位
int i,j;
while (loop --) {
i = startx;
j = starty;
// 下面开始的四个for就是模拟转了一圈
// 模拟填充上行从左到右(左闭右开)
for (j = starty; j < n - offset; j++) {
res[startx][j] = count++;
}
// 模拟填充右列从上到下(左闭右开)
for (i = startx; i < n - offset; i++) {
res[i][j] = count++;
}
// 模拟填充下行从右到左(左闭右开)
for (; j > starty; j--) {
res[i][j] = count++;
}
// 模拟填充左列从下到上(左闭右开)
for (; i > startx; i--) {
res[i][j] = count++;
}
// 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
startx++;
starty++;
// offset 控制每一圈里每一条边遍历的长度
offset += 1;
}
// 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
if (n % 2) {
res[mid][mid] = count;
}
return res;
}
};
代码直接抄 再看看学习下吧 之后再写。
总结:
再多看看滑动窗口和螺旋矩阵这个题吧