我们直接通过下面一道例题进行双指针方法的引入
思路
代码
void moveZeroes(vector<int>& nums) {
// cur: 从左到右遍历数组,dest: 非零元素的最后一个位置
// [0, dest] 非零 [dest+1, cur-1] 零 [cur+1, n-1] 未处理
int cur = 0, dest = -1;
for(cur = 0; cur < nums.size(); ++cur)
{
if(nums[cur] != 0)
std::swap(nums[++dest], nums[cur]);
}
}
思路
代码
void duplicateZeros(vector<int>& arr) {
int cur = 0, dest = -1;
int n = arr.size();
// 先找到最后一个复写的数
while(dest < n - 1)
{
// num[cur] 不为0,cur,dest后移一步,为零cur后移一步dest后移两步
if(arr[cur] != 0) dest++;
else dest += 2;
if(dest >= n-1) break;
cur++;
}
// 处理边界情况 如[1, 0, 2, 3, 0, 4]
if(dest == n)
{
arr[n-1] = 0;
dest-=2, cur--;
}
// 从后向前复写
while(cur >= 0)
{
if(arr[cur] != 0)
{
arr[dest--] = arr[cur];
}
else
{ // nums[cur] 为零,复写两次
arr[dest--] = 0;
arr[dest--] = 0;
}
cur--;
}
}
思路
代码
// 求每位平方和
int bitSquare(int n)
{
int sum = 0;
while(n > 0)
{
int bit = n % 10;
sum += bit * bit;
n /= 10;
}
return sum;
}
bool isHappy(int n) {
// 由已知得,数字一定成环,当slow与fast相遇
// 如果相遇位置值为1,则是快乐数
int slow = n, fast = bitSquare(n);;
while(slow != fast)
{
// 慢指针每次一步,快指针每次两步
slow = bitSquare(slow);
fast = bitSquare(bitSquare(fast));
}
return fast == 1;
}
思路
解法一:暴力解法:
解法二:利用单调性,使用双指针法
有了双指针法的前提算法思想,我们可以总结出步骤:
代码
int maxArea(vector<int>& height) {
int left = 0, right = height.size() - 1, ret = 0;
while(left < right)
{
// 算出本次体积
int v = min(height[left], height[right]) * (right - left);
ret = max(ret, v);
// 调整指针
if(height[left] > height[right]){
right--;
}
else{
left++;
}
}
return ret;
}
思路
for(int i = 0; i < n-1; ++i)
for(int j = i + 1; j < n - 1; ++j)
for(int k = j + 1; k < n - 1; ++k)
check(i, j, k); // 省略具体步骤
解法二:根据单调性用双指针法
2. 则思路如下:
代码
// 给定一个包含非负整数的数组 nums ,返回其中可以组成三角形三条边的三元组个数
int triangleNumber(vector<int>& nums) {
std::sort(nums.begin(), nums.end()); // 先排序数组
int n = nums.size(), count = 0;
// 外层for循环 控制最大数
for(int i = n - 1; i >= 1; --i)
{
int left = 0, right = i - 1;
while(left < right)
{
if(nums[left] + nums[right] <= nums[i]) left++;
else { // 如果 left + right > 最大数,则区间内的所有left与right组合均满足三角形
count += right - left;
right--;
}
}
}
return count;
}
思路
for(int i = 0; i < n; ++i)
for(int j = i + 1; j < n - 1; ++j)
check(nums[i] + nums[j] == target);
代码
vector<int> twoSum(vector<int>& price, int target) {
int n = price.size();
int left = 0, right = n - 1;
while(left < right)
{
int sum = price[left] + price[right]; // 记录两数和
if(sum < target)
left++;
else if (sum > target)
right--;
else
return {price[left], price[right]};
}
return {};
}
思路
解法一:排序+暴力枚举+使用set去重
解法二:排序+双指针法
代码
vector<vector<int>> threeSum(vector<int>& nums) {
// 排序数组 便于后面去重等
std::sort(nums.begin(), nums.end());
int n = nums.size();
vector<vector<int>> ret;
// for循环固定第一个数,则固定的数后的序列进行“找和为target的两个数”
// 如果 i = -5, 则target = 5
for(int i = 0; i < n - 2; ++i)
{
// 如果固定的数重复,跳过重复的数
if(i > 0 && nums[i] == nums[i-1]) continue;
int left = i + 1, right = n - 1;
while(left < right)
{
int sum = nums[i] + nums[left] + nums[right];
if(sum < 0)
{
left++;
}
else if(sum > 0)
{
right--;
}
else // 找到满足的数,插入到ret中,并更新left和right
{
ret.push_back({nums[i], nums[left], nums[right]});
// 判断left和right的下一位是否重复,如果重复则跳过重复的数
while(left < right && nums[left] == nums[left+1]) {
left++;
}
while(left < right && nums[right] == nums[right-1]) {
right--;
}
left++, right--;
}
}
}
return ret;
}
思路
代码