【leetcode】链表刷题tricks

链表的类型:单链表、双链表、循环链表

链表节点的定义:

class ListNode:
    def __init__(self, val, next=None):
        self.val = val
        self.next = next

链表操作中一个重要的技巧是虚拟头节点:链表操作当前节点必须要找前一个节点才能操作,这就造成了头结点的尴尬,因为头结点没有前一个节点了,每次头结点都要单独处理,使用虚拟头结点可以简化代码

双指针的应用

LeetCode142题 环形链表II

快慢指针 + 数学推导

快慢指针如果相遇,说明有环;此时让慢指针回到头节点,再同速度移动两个指针,相遇节点即为环的入口

2 * (t + k1 * c + c0) = t + k2 * c + c0 -> t = (k2 - 2 * k1) * c - c0

# 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 = head
        slow = head
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            if fast == slow:
                break
        if fast is None or fast.next is None:
            return None
        slow = head
        while slow != fast:
            slow = slow.next
            fast = fast.next
        return fast

LeetCode160题 相交链表

双指针移动,使得两个链表尾部对齐,此时同时移动两个指针,相等的节点就是相交的节点

# 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]:
        cur_a, cur_b = headA, headB
        while cur_a and cur_b:
            cur_a = cur_a.next
            cur_b = cur_b.next
        if cur_a:
            cur = cur_a
            cur_l, cur_s = headA, headB
        else:
            cur = cur_b
            cur_l, cur_s = headB, headA
        while cur:
            cur = cur.next
            cur_l = cur_l.next
        while cur_l and cur_s:
            if cur_l == cur_s:
                return cur_l
            cur_l = cur_l.next
            cur_s = cur_s.next
        return None

 LeetCode19题 删除链表的倒数第N个节点

设置虚拟头结点,以方便处理删除实际头结点的逻辑

使用快慢指针,先让快指针移动到第N个节点上,然后快慢指针同时移动,当快指针移动到末尾节点时,慢指针的下一个节点就是要删除的倒数第N个节点

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def removeNthFromEnd(self, head, n):
        """
        :type head: ListNode
        :type n: int
        :rtype: ListNode
        """
        dummy_head = ListNode(next=head)
        slow = dummy_head
        fast = dummy_head
        for i in range(n):
            fast = fast.next
        while fast.next:
            slow = slow.next
            fast = fast.next
        slow.next = slow.next.next
        return dummy_head.next

 LeetCode86题 分隔链表

把原链表分成两个小链表,一个链表中的元素大小都小于x,另一个链表中的元素都大于等于x,最后再把这两条链表接到一起,就得到了想要的结果,需要注意每一步要断开原链表中的每个节点的next指针,否则会超出内存限制

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def partition(self, head: Optional[ListNode], x: int) -> Optional[ListNode]:
        small_dummy = ListNode()
        big_dummy = ListNode()
        small_cur, big_cur = small_dummy, big_dummy
        while head:
            if head.val >= x:
                big_cur.next = head
                big_cur = big_cur.next
                head = head.next
                # 断开原链表中的每个节点的next指针
                big_cur.next = None
            else:
                small_cur.next = head
                small_cur = small_cur.next
                head = head.next
                # 断开原链表中的每个节点的next指针
                small_cur.next = None
        small_cur.next = big_dummy.next
        return small_dummy.next

反转链表

LeetCode206题 反转链表

迭代法

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        dummy = ListNode()
        while head:
            tmp = dummy.next
            dummy.next = head
            head = head.next
            dummy.next.next = tmp
        return dummy.next

递归法

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if not head or not head.next:
            return head
        last = self.reverseList(head.next)
        head.next.next = head
        head.next = None
        return last

LeetCode92题 反转链表II

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseBetween(self, head: Optional[ListNode], left: int, right: int) -> Optional[ListNode]:
        if left == 1:
            return self.reverseN(head, right)
        head.next = self.reverseBetween(head.next, left - 1, right - 1)
        return head
    
    def reverseN(self, head, n):
        # 反转前n个节点的函数
        global n_1
        if n == 1:
            n_1 = head.next
            return head
        last = self.reverseN(head.next, n - 1)
        head.next.next = head
        head.next = n_1
        return last

LeetCode25题 K个一组翻转链表

遍历链表,记录节点数量,对满足k长度的一段链表进行反转,然后继续遍历直至结束

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
        dummy = ListNode()
        count = 0
        fast = head
        slow = head
        cur = dummy
        while fast:
            count += 1
            if count % k == 0:
                tmp = fast.next
                fast.next = None
                cur.next = self.reverse(slow)
                cur = slow
                fast = tmp
                slow = tmp
            else:
                fast = fast.next
        if cur:
            cur.next = slow
        return dummy.next

    def reverse(self, head):
        if not head or not head.next:
            return head
        last = self.reverse(head.next)
        head.next.next = head
        head.next = None
        return last

LeetCode234题 回文链表

用快慢指针遍历到中间节点,对后半部分进行反转,然后顺序比较链表值

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def isPalindrome(self, head: Optional[ListNode]) -> bool:
        fast = head
        slow = head
        while fast and fast.next and fast.next.next:
            fast = fast.next.next
            slow = slow.next
        reverse = self.reverseList(slow.next)
        while head and reverse:
            if head.val != reverse.val:
                return False
            head = head.next
            reverse = reverse.next
        return True
    
    def reverseList(self, head):
        if not head or not head.next:
            return head
        last = self.reverseList(head.next)
        head.next.next = head
        head.next = None
        return last

链表与优先队列的结合

LeetCode23题 合并K个升序链表

优先队列应用:把链表节点放入一个最小堆,就可以每次获得k个节点中的最小节点,算法整体的时间复杂度是O(nlogk),其中k是链表的条数,n是这些链表的节点总数

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

class Solution:
    def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
        import heapq
        dummy = ListNode()
        cur = dummy
        head = []
        for i in range(len(lists)):
            if lists[i]:
                heapq.heappush(head, (lists[i].val, i))
                lists[i] = lists[i].next
        while head:
            val, idx = heapq.heappop(head)
            cur.next = ListNode(val)
            cur = cur.next
            if lists[idx]:
                heapq.heappush(head, (lists[idx].val, idx))
                lists[idx] = lists[idx].next
        return dummy.next

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值