20200612-判断链表有环

1.1 判断链表有环

这2道题都和判断链表是否有环相关,看下给的例子

Input: head = [3,2,0,-4], pos = 1
Output: true
Explanation: There is a cycle in the linked list, where tail connects to the second node.

list cycle

对于这样一个带环的链表,判断是否有环,最简单的做法就是遍历所有的节点,如果遇到重复的节点,则说明有环,由此解法便是,用一个 visitedSet 来装已遍历过的节点,当遇到重复的节点,则说明有环,第一次遍历到的重复节点便是环的入口,这个解法需要额外提供一个 Set 空间,若是要求使用 O(1)空间复杂度,就有了另外一个思路:

使用一个快指针和一个慢指针来遍历 list, 如果链表有环,则必然存在在某一个节点上2个指针相遇。

public boolean hasCycle(ListNode head) {
        	if (head == null || head.next == null) {
                return false;
            }
            ListNode slow = head;
            ListNode fast = head.next;
            while (slow != fast) {
                if (fast == null || fast.next == null) {
                    return false;
                }
                slow = slow.next;
                fast = fast.next.next;
            }
            return true;
    }

如果要找出环的入口位置呢?这里就涉及一点点数学的上换算了:

假设链表 head 到环入口的节点数为 a(不包含入口节点),环的长度为b, 慢指针走过的路程为 s,快指针走过的路程为f, 当2个指针第一次相遇时,则有如下关系:

  • 第一次相遇:
  1. f = 2s (快指针每次走2步,慢指针每次走1步,所以相遇时路程是 2倍)
  2. f = s + k*b

这个公式就不太好理解, 假设相遇时的节点距离入口的距离为d, Slow 绕圈为 m, Fast 绕圈为 n, 则:

  • s = a + d + m*b;
  • f = a + d + n*b;

换算一下就得出,f = (n-m)*b + s; (n>m, 快指针绕圈更多),即 f = s + k * b;

我们将1,2 消一下就得到,s = k * b, 所以说慢指针走了环的 k 圈,若此刻有一个节点从 head 处开始走,它每次路过环入口的时机应该在 a + k * b(k 为绕圈数),由于慢指针 s=k * b, 所以让一个节点从头开始走,当它们相遇时,即为环的入口了。

1.2 反转链表

还有一类经典的链表题是反转链表,自己做题的过程中发现要注意的点:

  • 如何准确的处理节点之间的关系,先链接后面的关系(先使节点有多个父节点),再修改节点链接
  • 知道哪个是 head 节点,比如全部反转的 list 来说,最后一个节点是新的Head, 对 swap nodes in pairs来说新的 head 是第2个节点,对reverse nodes in k-gourp来说,新的 head 是第一组的最后一个节点
  1. 那么对于全反转来说 prev 走到最后一个节点就是新的 Head
ListNode prev=null;
ListNode cur=head;
while(cur != null){
    ListNode next = cur.next;
    cur.next = prev;
    prev = cur;
    cur = next;
}
return prev;
  1. 对于不是最后指针的位置是新 head的,都使用 dummy 来链接新的 Head
ListNode dummy= new ListNode(-1);
dummy.next = head;

mmy` 来链接新的 Head

ListNode dummy= new ListNode(-1);
dummy.next = head;

当 reverse 完毕后, dummy.next指向新的 head.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

带着天使反上帝 - Kaybee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值