目录
1、双指针遍历分割:避免开空间,原地处理
2、快慢指针:循环条件下的判断
3、左右指针(对撞指针):分析具有单调性,避免重复计算
双指针又分为双指针遍历分割,快慢指针和左右指针
1、双指针遍历分割:避免开空间,原地处理
(概念)核心思想:将数组分为两端、已处理的的部分,未处理的部分,cur遍历数组,指向未完成的数组,同时处理数组元素。dest指向处理完成的部分。
算法实际操作:cur指向第一个待处理的元素。dest指向处理完元素存放的位置,根据 cur指向数据的类型,进行不同操作。
例题:移动零
1089. 复写零 - 力扣(LeetCode)
class Solution {
public:void moveZeroes(vector<int>& nums) {int n=nums.size();for(int cur=0,dest=-1;cur<nums.size();){if(nums[cur]){//非0的顺序不变,那么按序处理非0swap(nums[cur],nums[++dest]);}cur++;}}
};
class Solution {
public:void duplicateZeros(vector<int>& arr) {int cur=0,dest=-1,n=arr.size();while(cur<n){if(arr[cur]) dest++;else dest+=2;if(dest>=n-1) break;cur++;}if(dest==n){arr[n-1]=0;dest=n-2;cur--;}while(cur>=0){if(arr[cur]) arr[dest--]=arr[cur--];else{arr[dest--]=0;arr[dest--]=0;cur--;}}}
};
2、快慢指针:循环条件下的判断
核心思想:经过分析,对于存在循环情况的问题,我们可以设置快慢指针来处理
.快乐数ss
class Solution {
public:int bitsum(int n){int sum=0;while(n){int i=n%10;n/=10;sum+=i*i;}return sum;}//快慢指针,不论是否是快乐数,都会进入循环,要不循环1为快乐数,要不是一堆数依次循环bool isHappy(int n) {int slow=n,fast=bitsum(n);while(slow!=1){slow=bitsum(slow);fast=bitsum(bitsum(fast));if(slow==fast&&slow!=1)return false;}return true;}
};
快乐数:分析可知必存在循环,分为1循环和多个数循环,然后利用快慢指针在循环中的前进速率不同,若相遇,判断循环数为多少,即可判断是否是快乐数
3、左右指针(对撞指针):分析具有单调性,避免重复计算
核心思想:在暴击解法上,利用单调性,避免重复计算,
11. 盛最多水的容器 - 力扣(LeetCode)
class Solution {
public:int maxArea(vector<int>& height) {int n=height.size();int left=0,right=n-1;int ret=(right-left)*min(height[left],height[right]);//记录最大值while(left<right){if(height[left]<=height[right]){left++;}else{right--;}ret=max(ret,(right-left)*min(height[left],height[right]));}return ret;}
};
实现操作:定义左右指针,left=0,right=n-1,ret=H*W,left和right向中间靠近的话,w一定减小,h只有增大才能实现ret变大。
611. 有效三角形的个数 - 力扣(LeetCode)
class Solution {
public:void duplicateZeros(vector<int>& arr) {int cur=0,dest=-1,n=arr.size();while(cur<n){if(arr[cur]) dest++;else dest+=2;if(dest>=n-1) break;cur++;}if(dest==n){arr[n-1]=0;dest=n-2;cur--;}while(cur>=0){if(arr[cur]) arr[dest--]=arr[cur--];else{arr[dest--]=0;arr[dest--]=0;cur--;}}}
};
暴力枚举三层循环
简化:排序后,固定两个值——三角形中较大的那两个,然后移动较小的那个值,变成求在某一有序区间内大于某值的个数。(利用单调性)
LCR 179. 查找总价格为目标值的两个商品 - 力扣(LeetCode)
class Solution {
public:vector<int> twoSum(vector<int>& price, int target) {int n=price.size();int low=0,height=n-1;while(low<height){if(price[low]+price[height]<target){low++;}else if(price[low]+price[height]>target){height--;}else{break;}}return {price[low],price[height]};}
};
暴力枚举+利用单调性优化:类盛水容器
class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {sort(nums.begin(),nums.end());int n=nums.size();vector<vector<int>> ret;for(int k=0;k<n-2;){int left=k+1,right=n-1;int target=-nums[k];while(left<right){if(nums[left]+nums[right]<target){left++;}else if(nums[left]+nums[right]>target){right--;}else{ret.push_back(vector<int>{nums[k],nums[left],nums[right]});left++;right--;while(left<right&&nums[left]==nums[left-1])left++;//细节问题:不重复同时判断不越界:left<rightwhile(left<right&&nums[right]==nums[right+1])right--;}}k++;while(k<n-2&&nums[k]==nums[k-1])k++;}return ret;}
};
18. 四数之和 - 力扣(LeetCode)
类上,对内两层的暴力改为求目标值
class Solution {
public:vector<vector<int>> fourSum(vector<int>& nums, int target) {int n=nums.size();sort(nums.begin(),nums.end());vector<vector<int>> ret;for(int x=0;x<n-3;){//固定第一个数for(int k=x+1;k<n-2;){//固定第二个数long long targeti=(long long)target-(nums[x]+nums[k]);for(int left=k+1,right=n-1;left<right;){long long sum=nums[left]+nums[right];if(sum>targeti){right--;}else if( targeti>sum){left++;}else{ret.push_back(vector<int>{nums[x],nums[k],nums[left],nums[right]});left++;right--;while(left<right&&nums[left]==nums[left-1]) left++;//注意仅仅,找到target去重,未找到的话,前面那个值未被统计不同去重while(left<right&&nums[right]==nums[right+1]) right--;}}k++;while(k<n-2&&nums[k]==nums[k-1]) k++;}x++;while(x<n-3&&nums[x]==nums[x-1]) x++;}return ret;}
};