双指针
双指针的核心思路
对撞指针:两个指针从序列的两端向中间移动,适用于有序数组或需要从两端逼近的问题。
快慢指针:两个指针从同一端开始,一个移动较快,一个移动较慢,适用于判断条件是否满足或比较元素间相对关系的问题。
双指针经典题型:
leetcode:661(有效三角形个数)
解法分析:排序 + 双指针 + 利用单调性
:https://leetcode.cn/problems/valid-triangle-number/
https://leetcode.cn/problems/valid-triangle-number/
class Solution {
void quiksort(vector<int>& nums,int l,int r){//快排将数组有序化
if(l >= r)
return;
int i = l - 1, j = r + 1,x = nums[(i + j) >> 1];
while(i < j){
do i++;while(nums[i] < x);
do j--;while(nums[j] > x);
if(i < j)
swap(nums[i],nums[j]);
}
quiksort(nums,l,j);
quiksort(nums,j + 1,r);
}
public:
int triangleNumber(vector<int>& nums) {
quiksort(nums,0,nums.size() - 1);
int sum = 0;
//当数组有序后可以发现
//我们可以确定三个数中的最大值
//然后利用双指针来判断是否满足三角形成立条件
for(int i = nums.size() - 1;i >= 2;i--){//for循环确定最大值
int l = 0;
int r = i - 1;
while(l < r){//双指针判断是否满足三角形形成条件
if(nums[l] + nums[r] > nums[i]){//如果(nums[l] + num[r] > nums[i])那么里面的数也一定能形成
//三角形
sum += (r - l);
r--;
}else{
//否则的话左指针++增大三个数中的最小值后继续判断
l++;
}
}
}
return sum;
}
};
leetcode:LCR179(查找总价格为目标值的两个商品)
解法分析:双指针 + 二分
class Solution {
public:
vector<int> twoSum(vector<int>& price, int target) {
int l = 0,r = price.size() - 1;//初始化左右指针
vector<int> nums;
while(l < r){
if(price[l] + price[r] < target)//总值小于要找的值l++
l++;
else if(price[l] + price[r] > target)//总值大于要找的值r--
r--;
else{//总值等于要找的值返回
nums.push_back(price[l]);
nums.push_back(price[r]);
return nums;
}
}
return nums;
}
};
leetocde:15(三数之和)
https://leetcode.cn/problems/3sum/https://leetcode.cn/problems/3sum/
解法分析:排序 + 枚举 + 双指针 + 去重(set)
class Solution {
void quiksort(vector<int>& nums,int l,int r){//进行一遍快排方便后续使用双指针
if(l >= r)
return;
int i = l - 1,j = r + 1,x = nums[(l + r) >> 1];
while(i < j){
do i++; while(nums[i] < x);
do j--; while(nums[j] > x);
if(i < j){
swap(nums[i],nums[j]);
}
}
quiksort(nums,l,j);
quiksort(nums,j+1,r);
}
public:
vector<vector<int>> threeSum(vector<int>& nums) {
quiksort(nums,0,nums.size() - 1);
vector<vector<int>> vv;
set<vector<int>> s;//利用set容器的特性去掉重复的值
for(int i = 0;i < nums.size()-2;i++){//固定第三个数用双指针来查找接下来的两个数
int l = i + 1,r = nums.size() - 1;
while(l < r){
if(nums[l] + nums[r] == -nums[i]){//当两个指针代表的数之和等于固定的数的负数的时候就是找到了
s.insert({nums[i],nums[l],nums[r]});//插入
l++;//这里注意要变换两个指针的位置进入下一次循环否则会导致死循环
r--;
}
else if(nums[l] + nums[r] > -nums[i])//大于情况
r--;
else//小于情况
l++;
}
}
for(auto& e : s){//for-each把双指针查询得到的每一个数组值插入进vv中
vv.push_back(e);
}
return vv;//返回
}
};
思考:这道题如果不用set去重的话因该怎么做?
class Solution {
void quiksort(vector<int>& nums,int l,int r){
if(l >= r)
return;
int i = l - 1,j = r + 1,x = nums[(l + r) >> 1];
while(i < j){
do i++; while(nums[i] < x);
do j--; while(nums[j] > x);
if(i < j){
swap(nums[i],nums[j]);
}
}
quiksort(nums,l,j);
quiksort(nums,j+1,r);
}
public:
vector<vector<int>> threeSum(vector<int>& nums) {
quiksort(nums,0,nums.size() - 1);
vector<vector<int>> vv;
for(int i = 0;i < nums.size()-2;i++){//遍历第三个数
if(i > 0 && nums[i] == nums[i-1])//跳过固定数重复的情况
continue;
int l = i + 1,r = nums.size() - 1;
while(l < r){
if(nums[r] + nums[l] == -nums[i]){//找出符合条件的三个数
vv.push_back({nums[i],nums[l],nums[r]});
r--;//向中移动
l++;
//跳过后面重复的符合条件的数
while (l < r && nums[l] == nums[l - 1]) l++;
while (l < r && nums[r] == nums[r + 1]) r--;
}
else if(nums[r] + nums[l] > -nums[i])
{r--;
}
else if(nums[r] + nums[l] < -nums[i])
{l++;
}
}
}
return vv;
}
};