返回文章列表

快慢指针

2026年3月28日4 分钟阅读

算法进阶:彻底搞懂“快慢指针”及其妙用

在处理链表(Linked List)或循环数组问题时,传统的单指针遍历往往显得力不从心。今天我们要聊的 快慢指针(Fast & Slow Pointers),通过“步频差异”这一巧妙设计,能优雅地解决许多看似复杂的时间与空间复杂度挑战。


1. 什么是快慢指针?

顾名思义,我们同时使用两个指针在数据结构上移动:

  • 慢指针 (Slow):每次向前移动 1 个步长。
  • 快指针 (Fast):每次向前移动 2 个(或更多)步长。

这种步频差就像“龟兔赛跑”,只要路程足够长或存在环路,快指针一定会与慢指针产生特定的相对位置关系,从而帮助我们推导出结构的特征。


2. 核心应用场景

① 判定链表是否有环 (Floyd's Cycle-Finding Algorithm)

这是快慢指针最经典的应用,也被称为“龟兔赛跑算法”。

  • 逻辑:如果链表中存在环,快指针最终会进入环并在某个时刻“套圈”慢指针,两者在环内相遇。
  • 优势:空间复杂度仅为 O(1),不需要额外的哈希表存储访问记录,极大地节省了内存。

② 寻找链表的中点

在不预先知道链表长度的情况下,如何仅通过一次遍历找到中点?

  • 逻辑:快指针的速度是慢指针的两倍。当快指针到达链表末尾(null)时,慢指针刚好走到了全长的一半。
  • 用途:常用于链表的归并排序(Merge Sort)或判断回文链表。

③ 寻找环的入口点

这是一个进阶的数学问题。

  • 逻辑:在快慢指针第一次相遇后,将其中一个指针放回起点(Head),两个指针现在以相同速度(步长皆为 1)同时前进。当它们再次相遇时,相遇点即为环的入口。

3. 代码演示 (C语言实现)

  • 判断链表是否有环
  • 返回 1 表示有环,返回 0 表示无环
int isCycle(Node *head) 
{
   Node *fast = head;
   Node *slow = head;

   while (fast != NULL && fast->next != NULL)   //这里的while循环条件是fast指针和fast指针的下一个节点都不为NULL,确保fast指针不会越界.
   {
       fast = fast->next->next; // 快指针每次走两步
       slow = slow->next;        // 慢指针每次走一步

       if (fast == slow)        // 快慢指针相遇,说明有环
       {
           return 1;
       }
   }

   return 0; // 快指针走到尽头,说明无环
}
  • 找到链表环的入口
  • 返回环的起始节点指针
Node* findBegin(Node *head)
{
   Node *fast = head;
   Node *slow = head;

   // 第一步:利用快慢指针判断是否有环
   while (fast != NULL && fast->next != NULL)
   {
       fast = fast->next->next;
       slow = slow->next;

       // 如果相遇,说明有环
       if (fast == slow)
       {
           // 第二步:计算环中节点的个数 count
           Node *p = fast;
           int count = 1;
           while (p->next != slow)
           {
               count++;
               p = p->next;
           }

           // 第三步:寻找环的入口
           fast = head;
           slow = head;

           // 让 fast 指针先走 count 步
           for (int i = 0; i < count; i++)
           {
               fast = fast->next;
           }

           // 然后 fast 和 slow 同步前进,相遇点即为入口
           while (fast != slow)
           {
               fast = fast->next;
               slow = slow->next;
           }
           
           return slow;
       }
   }

   return NULL; // 无环
}

4. 为什么这个技巧很重要?

  • 极高的空间效率:它能将原本需要 O(n) 空间的算法(例如使用哈希表或集合来记录已访问节点)降低到 O(1) 的常数级空间。
  • 打破思维定式:它提醒我们,遍历数据结构时不一定只有一种速度。通过制造“速度差”,我们可以巧妙地挖掘出链表或数组中隐藏的几何属性(如中点、环路等)。

结语

快慢指针是算法面试中的“常客”,也是提升程序效率的利器。下次当你看到链表、循环或需要寻找特定比例位置的问题时,不妨停下来想想:是不是可以让其中一个指针“跑快点”?

发表评论