【力扣探索】链表——双指针技巧

链表的双指针技巧

经典环绕问题

问题:给定一个链表,判断其中有无环

链表中使用两个速度不同的指针时会遇到的情况:

  1. 如果没有环,快指针将停在链表的末尾。
  2. 如果有环,快指针最终将与慢指针相遇

两个指针的速度应该如何设置?
3. 安全的选择是每次移动慢指针一步,而移动快指针两步。每一次迭代,快速指针将额外移动一步。如果环的长度为 M,经过 M 次迭代后,快指针肯定会多绕环一周,并赶上慢指针。
4. 其他选择?有用吗? 会更高效么?

链表双指针解题模板

在这里,我们为你提供了一个模板,用于解决链表中的双指针问题。

// Initialize slow & fast pointers
ListNode* slow = head;
ListNode* fast = head;
/**
 * Change this condition to fit specific problem.
 * Attention: remember to avoid null-pointer error
 **/
while (slow && fast && fast->next) {
   
    slow = slow->next;          // move slow pointer one step each time
    fast = fast->next->next;    // move fast pointer two steps each time
    if (slow == fast) {
            // change this condition to fit specific problem
        return true;
    }
}
return false;   // change return value to fit specific problem

Tips

1. 在调用 next 字段之前,始终检查节点是否为空
获取空节点的下一个节点将导致空指针错误。例如,在我们运行 fast = fast.next.next 之前,需要检查 fast 和 fast.next 不为空。
2. 仔细定义循环的结束条件。
运行几个示例,确保结束条件不会导致无限循环。在定义结束条件时,你必须考虑我们的第一点提示。
3. 复杂度分析
空间复杂度分析容易。如果只使用指针,而不使用任何其他额外的空间,那么空间复杂度将是 O(1)。但是,时间复杂度的分析比较困难,我们需要分析运行循环的次数。

练习

1. 环形链表

题目链接: 141. 环形链表.
解题思路

  1. 快慢指针,原则上设置快指针速度为M,慢指针速度为N,当M-N=1且存在环时,两者必然会在环内相遇,更概括的,当相遇的时候,快指针多跑了若干个环的长度(设环长为L),只要两者的速度差满足L%(M-N) = 0或者(M-N) = k*L(k为正整数)即可。
  2. 逐个删除,一个链表从头节点开始一个个删除,所谓删除就是让他的next指针指向他自己。如果没有环,从头结点一个个删除,最后肯定会删完;如果是环形的,那么有两种情况,一种是o型的,一种是6型的,删到最后,肯定会出现head=head.next,详情见逐个删除思路解析
  3. 反转比较,关于链表的反转可以看下432,剑指 Offer-反转链表的3种方式。如果有环,那么链表反转之后,原来的头结点和反转之后的头结点一定是同一个.
  4. 存放集合,把节点存放到集合set中,每次存放的时候判断当前节点是否存在,如果存在,说明有环
  5. 哈希表,每次遍历到一个节点时,判断该节点此前是否被访问过,用哈希表来存储所有已经访问过的节点。每次我们到达一个节点,如果该节点已经存在于哈希表中,则说明该链表是环形链表,否则就将该节点加入哈希表中。重复这一过程,直到我们遍历完整个链表即可。

代码

//快慢指针版本1,时间O(N) 额外空间O(1)
class Solution {
   
public:
    bool hasCycle(ListNode *head) {
   
        if(head == NULL) return false;
        ListNode* fast = head;
        ListNode* slow = head;
  		while(slow != NULL && fast != NULL){
   
  			slow = slow->next;
  			if(fast->next != NULL){
   
  				fast = fast->next->next;
  			}
  			else break;
  			if(slow == fast) return true;	
  		} 
  		return false;     
    }
};

//快慢指针版本2,时间O(N) 额外空间O(1)
class Solution {
   
public:
    bool hasCycle(ListNode* head) {
   
        if (head == nullptr || head->
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值