Leetcode: 977有序数组的平方
基本思路
结合昨天学习到的双指针的思想。首先审题的过程中,发现数据存在负数,因此就存在负数的平方可能更大的情况,因此产生了数组排序的问题。但是整体数组的平方规律为先降低,然后在上升。因此最大数肯定存在两端。从而产生双指针从数组两端开始向中间搜索的策略。
时间复杂度O(n)
代码
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int left = 0, right = nums.size() - 1;
int k = right;//编程技巧:从数组的最后开始赋值,这样不用产生调换顺序的操作
vector<int> result(nums.size(),0);//对新的数组的定义,用空间换时间
while(left <= right){
if(nums[left] * nums[left] > nums[right] * nums[right]){
result[k] = nums[left] * nums[left];
left++;
k--;
}
else{//因为left=right的情况下,随便哪一个都行,因此不用单独分支
result[k] = nums[right] * nums[right];//注意最后输出的是平放,不要忘记乘了
right--;
k--;
}
}
return result;
}
};
Leetcode: 209最小长度的子数组
基本思路
这题的双指针起点从同侧开始,右指针移动快,左指针移动慢。当没有达到目标值的时候,移动右指针,当目标值达到的时候移动左指针。当左指针移动后就需要判断当前的长度是不是最小的,从而更新最小长度。最后输出结果。(也叫滑动窗)
代码
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int left = 0, right = 0, sum = 0;
int count = INT32_MAX;//用于判断count是否赋值,没有赋值就输出0
while(right < nums.size()){
sum = sum + nums[right];//右指针向右移动
while(sum >= target){//当和大于目标值的时候,左指针向右移动
sum = sum - nums[left];
if((right - left + 1) < count){//判断是否需要更新最小长度
count = right - left + 1;
}
left++;
}
right++;
}
return count == INT32_MAX ? 0 : count;//判断输出
}
};
附加题: 26 删除有序数组中的重复元素
本题主要考察双指针的应用,本身题目很简单,但是容易犯错,对一些等号和判断条件把握不准确。
如果 nums[fast]≠nums[fast−1],说明 nums[fast]和之前的元素都不同,因此可以更新慢指针。
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int fast = 1, slow = 1;//因为涉及到fast-1,如果初始化为0的话,会导致越界
if(nums.size() == 0) return 0;//特殊条件判断
for( ; fast <= nums.size() - 1; fast++){//第一层循环
if(nums[fast] != nums[fast - 1]){//当此条件的时候,一定是不重复的元素
nums[slow] = nums[fast];
slow++;
}
}
return slow;
}
};
Leetcode: 59 螺旋矩阵
一道基本的模拟题,整体思路不难,就是写不出来。。。(bushi)
主要错误点
- 参数太多了,没有规划容易搞混,或者定义少了,因此在开始之前需要预先思考需要多少个参数
- 不知道循环n/2圈
- 最后奇数的中间和偶数中间不一样,还有一个数字
- 没有定义好规则,需要秉承着左闭右开或者其他规则,防止重复统计位置,或者少了位置,或者条件判断失误,出现细小的问题
- 最好配合着画图,如果数字关系把握不准确,可以用笔算算
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {//二次矩阵的定义方式
int starti = 0, startj = 0, i = 0, j = 0;
int count = n / 2;//圈数定义
int number = 1;
int flag = 1;//循环边界条件定义
vector<vector<int>> res(n, vector<int>(n, 0));
while(count--){
i = starti;//起始位置更新
j = startj;
for( ; j < n - flag; j++){
res[i][j] = number;
number++;
}
for( ; i < n - flag ;i++){
res[i][j] = number;
number++;
}
for(;j > startj ;j--){
res[i][j] = number;
number++;
}
for(; i > starti; i--){
res[i][j] = number;
number++;
}
flag++;
starti++;
startj++;
}
if(n % 2){//如果是奇数,中间的数字
res[n/2][n/2] = n*n;
}
return res;
}
};
小结
今天主要联系了双指针的题目,在审题过程中需要思考
- 指针开始的方式和移动方向
- 快慢指针的更新规则,以及条件判断
- 小心数量关系的错误,导致边界条件不清晰