leetcode 链表+双指针问题小结

文章目录

    • 141. 环形链表
    • 142. 环形链表 II
    • 19. 删除链表的倒数第 N 个结点
    • 160. 相交链表

141. 环形链表

leetcode 链表+双指针问题小结_第1张图片
设置两个速度不一样的链表,如果其中他们两个在经过一定的步数(进入环之后,在 n × ∣ 环的大小 ∣ n \times |环的大小| n×环的大小 步后会重合)之后会重合,则说明有环。

# Definition for singly-linked list.
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None

class Solution:
    def hasCycle(self, head: Optional[ListNode]) -> bool:
        head_i = head
        head_j = head

        while(head_i is not None and head_j is not None):
            head_i = head_i.next
            head_j = head_j.next
            if head_j is None:
                return False
            else:
                head_j = head_j.next
            
            total += 1
            if head_i == head_j:
                return True
        
        return False

142. 环形链表 II

leetcode 链表+双指针问题小结_第2张图片
这里与上一题不同的地方在于需要求得环的入口。
设慢指针的步数为s,则第一次相遇时,快指针的步数为2s=s+nb,其中b为环的长度。化简可以得到s=nb。
在二者相遇之后,我们将快指针回退到head的位置。假设快指针又经过a步到达环的入口,此时慢指针步数为a+s=a+nb,一定也会到达环口。因此只需要再求出这时二者相遇的位置即可。

leetcode 链表+双指针问题小结_第3张图片

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def detectCycle(self, head):
        if not head:
            return None
        """
        :type head: ListNode
        :rtype: ListNode
        """
        head_slow = head
        head_fast = head

        while(True):
            if not head_fast.next or not head_fast.next.next:
                return None
            head_slow, head_fast = head_slow.next, head_fast.next.next
            if head_slow == head_fast:
                # 第一次相遇
                break

        head_fast = head
        while(head_fast != head_slow):
            head_fast, head_slow = head_fast.next, head_slow.next

        return head_fast

19. 删除链表的倒数第 N 个结点

leetcode 链表+双指针问题小结_第4张图片

这个让快指针先走n步就可以了。需要注意的是可以设置一个dummy head以处理只有一个node的情况。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
        dummy = ListNode(next=head)
        
        # 设置一个dummy head可以帮助处理只有一个节点的情况
        fast, slow = dummy, dummy
        for i in range(n):
            fast = fast.next

        while(fast.next != None):
            slow = slow.next
            fast = fast.next
        slow.next = slow.next.next

        return dummy.next

160. 相交链表

leetcode 链表+双指针问题小结_第5张图片
这一题的主要思路是两个head均设置一个指针,当某一个指针到达终点之后,去到对方的head重新开始走,走到交叉点一定会相遇,因为这时两个指针的路径长度都是a+b+c。
leetcode 链表+双指针问题小结_第6张图片

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]:

        pointerA = headA
        pointerB = headB
        # 当某一个指针到达终点之后,去到对方的head重新开始走,走到交叉点一定会相遇
        # 因为这时两个指针的路径长度都是a+b+c
        while(pointerA != pointerB):
            pointerA = pointerA.next if pointerA else headB 
            pointerB = pointerB.next if pointerB else headA 

        if pointerA == pointerB and pointerB is not None:
            return pointerA
            
        return None

你可能感兴趣的:(链表,leetcode,数据结构)