双指针
文章目录
~~~ 双指针可以用来解决 子数组问题,不过通常来说,使用双指针通常需要对原数组进行sort排序。
Leetcode11 盛最多水的容器
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。
输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
//(双指针法)取巧——设置左右端点,只会向内移动:短板向内移动(长板向内移动不可能使得面积变大)
class Solution {
public:
int maxArea(vector<int>& height) {
int n=height.size();
int s=min(height[0],height[n-1])*(n-1),max=0;
int i=0,j=n-1;
while(i<j)
{
s=min(height[i],height[j])*(j-i);
if(max<s)
max=s;
if(height[i]>height[j])
j--;
else if(height[i]==height[j])
{
j--;
i++;
}
else
i++;
}
return max;
}
};
Leetcode15 三数之和
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例1
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
提示:
0 <= nums.length <= 3000
-105 <= nums[i] <= 105
题解
三数之和,我们很容易得到思路是:确定两个数,遍历第三个数看是否nums[i]符合条件。我们可以用双指针来解决。有两种设置指针的思路。
【思路1】设置最左侧left,最右侧right,逐渐向内靠拢(常规)
【思路2】排序后循环遍历数组,第i次循环nums[i],设置left=i+1(nums[i]的左端),right=len-1(整个数组的最右端)。
nums[i]+nums[left]+nums[right] ==0 ? ①<0:L++ ②>0:R- - ③=0:L++ && R- -
双指针移动时注意重复元素即可。
class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> v;
int len=nums.size();
if(len<=2)
return v;
sort(nums.begin(),nums.end());
int L,R; //双指针
for(int i=0;i<len;i++)
{
if(nums[i]>0)
break;
L=i+1; R=len-1;
while(R>L)
{
if(nums[i]+nums[L]+nums[R]==0)
{
v.push_back({nums[i],nums[L],nums[R]});
while(R>L && nums[L]==nums[L+1])
L++;
while(R>L && nums[R]==nums[R-1])
R--;
L++;
R--;
}
else if(nums[i]+nums[L]+nums[R]>0)
R--;
else
L++;
}
while(i+1<len && nums[i]==nums[i+1])
i++;
}
return v;
}
};
Leetcode16 最接近的三数之和
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
int len=nums.size();
sort(nums.begin(),nums.end());
int ans;
for(int i=0;i<len;i++)
{
int start = i+1, end = len - 1;
while(start < end)
{
int sum = nums[start] + nums[end] + nums[i];
if(abs(target - sum) < abs(target - ans))
ans = sum;
if(sum > target)
end--;
else if(sum < target)
start++;
else
return ans;
}
}
return ans;
}
};
Leetcode18 四数之和
给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):
~~~~~~~~ 0 <= a, b, c, d < n
~~~~~~~~ a、b、c 和 d 互不相同
~~~~~~~~ nums[a] + nums[b] + nums[c] + nums[d] == target
输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
提示:
1 <= nums.length <= 200
- 1 0 9 10^9 109 <= nums[i] <= 1 0 9 10^9 109
- 1 0 9 10^9 109 <= target <= 1 0 9 10^9 109
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector <int>> v; //返回答案的二维数组
sort(nums.begin(),nums.end());
int len=nums.size();
int left,right; //双指针
if(len<4)
return v;
for(int i=0;i<len-3;i++)
{
for(int j=i+1;j<len-2;j++)
{
int sum=nums[i]+nums[j]; //前两数之和
left=j+1; right=len-1;
while(right>left)
{
long long x = static_cast<long long>(sum);
long long y = static_cast<long long>(nums[left]);
long long z = static_cast<long long>(nums[right]);
if(x+y+z>target)
right--;
else if(x+y+z<target)
left++;
else
{
v.push_back({nums[i],nums[j],nums[left],nums[right]});
while(right>left && nums[right]==nums[right-1])
right--;
while(right>left && nums[left]==nums[left+1])
left++;
right--;
left++;
}
}
while(j+3<len && nums[j]==nums[j+1])
j++;
}
while(i+4<len && nums[i]==nums[i+1])
i++;
}
return v;
}
};
Leetcode80 删除有序数组中的重复项 II
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
输入:nums = [1,1,1,2,2,3]
输出:5, nums = [1,1,2,2,3]
解释:函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。 不需要考虑数组中超出新长度后面的元素。
//双指针————子数组问题要考虑双指针
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int len=nums.size();
if(len<=2)
return len;
int slow=2,fast=2;
while(fast<len)
{
if(nums[slow-2]==nums[fast])
{
fast++;
}
else
{
nums[slow]=nums[fast];
slow++;
fast++;
}
}
return slow;
}
};