双指针算法精解:对撞指针与快慢指针的妙用与实践

 在算法学习中,双指针技巧是一种高效且实用的方法,能够显著降低时间复杂度,优化代码性能。

本文将深入探讨两种经典的双指针技术:对撞指针快慢指针,帮助你掌握其核心思想与应用场景。

01

对撞指针(Colliding Pointers)

1.细节

  • 定义:对撞指针使用两个指针,一个从数组的起始位置(左指针)开始,另一个从数组的末尾(右指针)开始,两个指针向中间移动,直到相遇或交叉。
  • 适用场景:通常用于有序数组或可以通过排序转化为有序数组的问题。
  • 时间复杂度:O(n),因为每个指针最多遍历数组一次。

2.思想

  • 核心思想:通过左右指针的协同移动,缩小问题的搜索范围。利用数组的有序性,通过比较指针指向的值与目标值的关系,决定移动哪个指针。
  • 优势:避免了暴力搜索的高时间复杂度(O(n^2)),将问题优化为线性时间复杂度。

3.功能

  • 典型应用:
  1. 两数之和:在有序数组中找到两个数,使它们的和等于目标值。
  2. 三数之和:找到数组中三个数,使它们的和等于目标值。
  3. 回文串判断:判断一个字符串是否为回文串。

4.代码示例

#include <vector>
#include <algorithm>
 
// 两数之和问题
std::vector<int> twoSum(std::vector<int>& nums, int target) 
{
    std::sort(nums.begin(), nums.end()); // 首先对数组排序
    int left = 0;
    int right = nums.size() - 1;
    while (left < right) 
    {
        int sum = nums[left] + nums[right];
        if (sum == target) 
        {
            return {nums[left], nums[right]}; // 返回找到的两个数
        } 
        else if (sum < target) 
        {
            left++; // 和小于目标值,左指针右移
        } 
        else 
        {
            right--; // 和大于目标值,右指针左移
        }
    }
    return {}; // 如果没有找到,返回空数组
}

02

左右指针(快慢指针,Slow-Fast Pointers)

1.细节

  • 定义:快慢指针使用两个指针,一个移动速度快(快指针),另一个移动速度慢(慢指针)。通常快指针每次移动两步,慢指针每次移动一步。
  • 适用场景:常用于链表或数组中的循环检测、中点查找、滑动窗口等问题。
  • 时间复杂度:O(n),因为每个指针最多遍历链表或数组一次。

2.思想

  • 核心思想:通过快慢指针的速度差,解决一些需要定位特定位置或检测特定模式的问题。例如,快指针的速度是慢指针的两倍,可以用来找到链表的中点或检测环。
  • 优势:避免了额外的空间开销(如使用哈希表),同时保持线性时间复杂度。

3.功能

  • 典型应用:
  • 链表环检测:判断链表中是否存在环。
  • 链表中点查找:找到链表的中点。
  • 滑动窗口:解决子数组或子字符串的相关问题。

4.代码示例

#include <iostream>
 
struct ListNode 
{
    int val;
    ListNode* next;
    ListNode(int x) : val(x), next(nullptr) {}
};
 
// 链表环检测
bool hasCycle(ListNode* head) 
{
    if (head == nullptr || head->next == nullptr) 
    {
        return false;
    }
    ListNode* slow = head; // 慢指针
    ListNode* fast = head; // 快指针
    while (fast != nullptr && fast->next != nullptr) 
    {
        slow = slow->next; // 慢指针每次移动一步
        fast = fast->next->next; // 快指针每次移动两步
        if (slow == fast) 
        {
            return true; // 快慢指针相遇,说明有环
        }
    }
    return false; // 无环
}
 
// 链表中点查找
ListNode* findMiddle(ListNode* head) 
{
    ListNode* slow = head;
    ListNode* fast = head;
    while (fast != nullptr && fast->next != nullptr) 
    {
        slow = slow->next; // 慢指针每次移动一步
        fast = fast->next->next; // 快指针每次移动两步
    }
    return slow; // 慢指针指向中点
}

03

总结

类型

细节

思想

功能

对撞指针

两个指针从两端向中间移动,适用于有序数组。

利用有序性缩小搜索范围,优化时间复杂度。

两数之和、三数之和、回文串判断等。

左右指针

快慢指针以不同速度移动,适用于链表或数组。

通过速度差定位特定位置或检测特定模式。

链表环检测、链表中点查找、滑动窗口等。

       双指针技术是一种非常实用的算法设计思想,能够有效解决许多经典问题。掌握对撞指针和左右指针的使用场景和实现细节,可以显著提升算法能力。

C/C++ 文章被收录于专栏

记录我的C++学习路程

全部评论

相关推荐

评论
2
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务