网站群建设系统武汉做seo
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 = 0j = len(nums)-1while(i<=j):if(nums[i]**2<nums[j]**2):result.append(nums[j]**2)j -= 1else:result.append(nums[i]**2)i += 1result.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 = 0i = 0subArrLength = 0for j in range(len(nums)):currentNum += nums[j]while(currentNum >= target):subArrLength = j - i + 1result = min(subArrLength,result)currentNum -= nums[i]i += 1return 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;}
};
代码直接抄 再看看学习下吧 之后再写。
总结:
再多看看滑动窗口和螺旋矩阵这个题吧