代码随想录训练营第四天 | 24. 两两交换链表中的节点 19.删除链表的倒数第N个节点 面试题 02.07. 链表相交 142.环形链表II

文章目录

  • 一、两两交换链表中的节点
  • 二、删除链表的倒数第N个节点
  • 三、链表相交
  • 四、环形链表Ⅱ
  • 总结

一、两两交换链表中的节点

leetcode 24 两两交换链表中的节点
思路:使用cur_ptrnext_ptr进行链表的节点交换,注意节点交换的顺序和while循环跳出的条件,注意next_ptrNone的情况。
note:并且还需要采用虚拟头结点来避免在交换头结点和第二个节点的时候出现的头结点错乱的情况

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
        dummyHead = ListNode(next = head)
        pre_ptr = dummyHead
        cur_ptr = head
        while cur_ptr and cur_ptr.next:
            node2 = cur_ptr.next
            node3 = node2.next

            pre_ptr.next = node2
            node2.next = cur_ptr
            cur_ptr.next = node3

            pre_ptr = cur_ptr
            cur_ptr = node3
        
        return dummyHead.next
            
        

二、删除链表的倒数第N个节点

leetcode 19 删除链表的倒数第N个节点
思路:两个指针fastslow,先让fast往前走N个节点,然后fastslow同时向后遍历,直至fast指针到链表尾。
注意点:注意最后slow.next才是那个想删除的节点

# 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]:
        dummyHead = ListNode(next = head)
        quick, slow = dummyHead, dummyHead
        for i in range(n):
            quick = quick.next
        
        while quick.next != None:
            quick = quick.next
            slow = slow.next
        
        slow.next = slow.next.next
        return dummyHead.next

三、链表相交

leetcode 面试题0207链表相交
思路:

  1. 先遍历,得到两个链表的长度len_a, len_b
  2. 把比较长的那个链表先往后遍历abs(len_a - len_b)个节点
  3. 一起遍历,直至两个指针相等,如果到最后没有相等的节点,返回None
# 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) -> ListNode:
        dummyHeadA = ListNode(next = headA)
        dummyHeadB = ListNode(next = headB)

        cur_node_a = headA
        cur_node_b = headB
        len_a, len_b = 0, 0
        while cur_node_a:
            len_a += 1
            cur_node_a = cur_node_a.next
        
        while cur_node_b:
            len_b += 1
            cur_node_b = cur_node_b.next
        
        start_a, start_b = headA, headB
        if len_a > len_b:
            for i in range(len_a - len_b):
                start_a = start_a.next
        else:
            for i in range(len_b - len_a):
                start_b = start_b.next
        

        while start_a:
            if start_a == start_b:
                return start_b
            else:
                start_a = start_a.next
                start_b = start_b.next
        
        return None

四、环形链表Ⅱ

leetcode 142 环形链表Ⅱ
首先需要判断链表内是否有环

  1. 初始化fast, slow两个指针,fast指针每次走两步,slow指针每次走一步
  2. 如果fast==slow,那么说明链表存在环
  3. 如果fast==None,那么说明无环

在确定链表有环的情况下,如何判断哪里是链表的环的入口呢?

  1. 假设链表分为三个部分:无环区域长度为out_loop,环内长度为loop,两个指针相遇时离入环区域距离len_enter
  2. out_loop + k_fast * loop + len_enter = 2 * (out_loop + len_enter + k_slow * loop)这里的k_fast和k_slow代表快指针和慢指针分别走过多少圈环
  3. 化简后发现,(k_fast - k_slow) * loop = out_loop + len_enter + k_slow * loop
  4. 也就是说,slow指针走过的步数一定是loop的整数倍
  5. 再进行化简,out_loop = (k_fast - 2 * k_slow - 1) * loop +(loop - len_enter)
  6. 这也就意味着,在现在的基础上再走out_loop步的话,就相当于fast指针在现在位置的基础上再走(k_fast - 2 * k_slow - 1)圈 + (loop - len_enter)步,此时fast也会回到环的入口

此时就可以完美地得到环的入口在哪里了,简单地来说,就是确定链表存在环路后,使得find_enter = head,然后使得find_enter = find_enter.nextfast = fast.next,直到fast == find_enter即可(注意保存入口的index)

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

class Solution:
    def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
        # 判断链表有没有环
        fast, slow = head, head
        while fast != None and fast.next != None:
            fast = fast.next.next
            slow = slow.next

            if fast == slow:
                find_enter = head
                while find_enter != fast:
                    find_enter = find_enter.next
                    fast = fast.next
                
                return fast
        
        return None
        

总结

最后一题需要一些数学推导,但是对链表的使用和认识非常重要。如果没有看懂可以去看代码随想录的解析

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