206. Reverse Linked List

  1. class Solution:
  2. def reverseList(self, head: ListNode) -> ListNode:
  3. if not head or not head.next:
  4. return head
  5. cur = self.reverseList(head.next) # 一路走到尾节点
  6. head.next.next = head
  7. head.next = None # 避免成环
  8. return cur # 永远返回新的头节点
  • 时间复杂度:链表 - 图1
  • 空间复杂度:链表 - 图2,取决于递归调用的栈空间

    1. class Solution:
    2. def reverseList(self, head: ListNode) -> ListNode:
    3. l, m = None, head
    4. while m:
    5. r = m.next
    6. m.next = l
    7. l, m = m, r
    8. return l
  • 时间复杂度:链表 - 图3

  • 空间复杂度:链表 - 图4

92. Reverse Linked List II

  1. class Solution:
  2. def reverseBetween(self, head: ListNode, left: int, right: int) -> ListNode:
  3. dummy = ListNode(-1, head)
  4. l, m = dummy, head
  5. for _ in range(left - 1):
  6. l, m = l.next, m.next
  7. for _ in range(right - left):
  8. r = m.next
  9. l.next, m.next, r.next = r, r.next, l.next
  10. return dummy.next
  1. class Solution:
  2. def reverseBetween(self, head: ListNode, left: int, right: int) -> ListNode:
  3. dummy = ListNode(-1, head)
  4. pre = nxt = l = r = dummy
  5. for _ in range(left - 1):
  6. pre = pre.next
  7. l = pre.next
  8. for _ in range(right):
  9. r = r.next
  10. nxt = r.next
  11. def reverse(head, tail): # 反转部分链表并返回'头and尾'
  12. tail.next = None # 以m为基准遍历,避免走出[head, tail]
  13. l, m = None, head
  14. while m:
  15. r = m.next
  16. m.next = l
  17. l, m = m, r
  18. return tail, head
  19. l, r = reverse(l, r)
  20. pre.next, r.next = l, nxt
  21. return dummy.next
  • 时间复杂度:链表 - 图5
  • 空间复杂度:链表 - 图6

25. Reverse Nodes in k-Group

  1. class Solution:
  2. def reverse(self, head, tail): # 翻转[head, tail]并返回'头and尾'
  3. tail.next = None
  4. l, m = None, head
  5. while m:
  6. r = m.next
  7. m.next = l
  8. l, m = m, r
  9. return tail, head
  10. def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
  11. if not head or not head.next:
  12. return head
  13. tail = head
  14. for _ in range(k - 1):
  15. tail = tail.next
  16. if not tail: # 不足k个元素,不执行翻转直接返回
  17. return head
  18. next_head = tail.next
  19. next_head = self.reverseKGroup(next_head, k) # 将后方链表翻转
  20. head, tail = self.reverse(head, tail)
  21. tail.next = next_head
  22. return head
  • 时间复杂度:链表 - 图7
  • 空间复杂度:链表 - 图8

    1. class Solution:
    2. def reverse(self, head, tail): # 翻转[head, tail]并返回'头and尾'
    3. tail.next = None
    4. l, m = None, head
    5. while m:
    6. r = m.next
    7. m.next = l
    8. l, m = m, r
    9. return tail, head
    10. def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
    11. dummy = ListNode(-1, head)
    12. pre = tail = dummy
    13. while head:
    14. for _ in range(k):
    15. tail = tail.next
    16. if not tail: # 长度不足k,不执行翻转
    17. return dummy.next
    18. next_head = tail.next
    19. head, tail = self.reverse(head, tail)
    20. pre.next, tail.next = head, next_head
    21. pre, head = tail, next_head
    22. return dummy.next
  • 时间复杂度:链表 - 图9

  • 空间复杂度:链表 - 图10

21. Merge Two Sorted Lists

  1. class Solution:
  2. def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
  3. if not list1:
  4. return list2
  5. elif not list2:
  6. return list1
  7. elif list1.val < list2.val:
  8. list1.next = self.mergeTwoLists(list1.next, list2)
  9. return list1
  10. else:
  11. list2.next = self.mergeTwoLists(list1, list2.next)
  12. return list2
  • 时间复杂度:链表 - 图11
  • 空间复杂度:链表 - 图12
  1. class Solution:
  2. def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
  3. dummy = ListNode(-1)
  4. p = dummy
  5. while list1 and list2:
  6. if list1.val < list2.val:
  7. p.next = list1
  8. list1 = list1.next
  9. else:
  10. p.next = list2
  11. list2 = list2.next
  12. p = p.next
  13. p.next = list1 if list1 else list2
  14. return dummy.next
  • 时间复杂度:链表 - 图13
  • 空间复杂度:链表 - 图14

23. Merge k Sorted Lists

class Solution:
    def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
        min_heap = []
        for i in range(len(lists)):
            if lists[i]:
                heapq.heappush(min_heap, (lists[i].val, i))
                lists[i] = lists[i].next

        dummy = ListNode(-1)
        p = dummy

        while min_heap:
            val, i = heapq.heappop(min_heap)
            p.next = ListNode(val)
            p = p.next

            if lists[i]:
                heapq.heappush(min_heap, (lists[i].val, i))
                lists[i] = lists[i].next

        return dummy.next
  • 时间复杂度:链表 - 图15
  • 空间复杂度:链表 - 图16,小根堆中的元素不超过链表 - 图17个(排序链表的数目)
class Solution:
    def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:

        def merge(lists, low, high):
            if low >= high:
                return lists[low]

            mid = low + high >> 1
            l1 = merge(lists, low, mid)
            l2 = merge(lists, mid+1, high)
            return merge_two_lists(l1, l2)

        def merge_two_lists(list1, list2):
            if not list1:
                return list2
            elif not list2:
                return list1
            elif list1.val < list2.val:
                list1.next = merge_two_lists(list1.next, list2)
                return list1
            else:
                list2.next = merge_two_lists(list1, list2.next)
                return list2

        if not lists:
            return
        return merge(lists, 0, len(lists) - 1)
  • 时间复杂度:链表 - 图18链表 - 图19是每个链表的最长长度
  • 空间复杂度:链表 - 图20

143. Reorder List 大杂烩

  1. 找到原链表中点
  2. 将后半段翻转,返回翻转后的头节点
  3. 合并(依次取一个链表的节点)两段链表

    class Solution:
     def reorderList(self, head: ListNode) -> None:
         def reverse_list(p):
             l, m = None, p
             while m:
                 r = m.next
                 m.next = l
                 l, m = m, r
             return l
    
         def merge_2_lists(l1, l2):
             while l1 and l2:
                 tmp1, tmp2 = l1.next, l2.next
                 l1.next, l2.next = l2, tmp1
                 l1, l2 = tmp1, tmp2
    
         dummy = ListNode(-1, head)
         slow = fast = dummy
         while fast and fast.next:       # slow停在前半段末尾
             slow = slow.next
             fast = fast.next.next
    
         p1, p2 = head, slow.next
         slow.next = None
         p2 = reverse_list(p2)           # 翻转后半部分
    
         merge_2_lists(p1, p2)
    
  • 时间复杂度:链表 - 图21
  • 空间复杂度:链表 - 图22

328. Odd Even Linked List

按奇偶分割 链表 - 图23 合并

class Solution:
    def oddEvenList(self, head: ListNode) -> ListNode:
        if not head or not head.next:
            return head

        odd_head, even_head = head, head.next
        odd, even = odd_head, even_head

        while even and even.next:
            odd.next = even.next
            odd = odd.next
            even.next = odd.next
            even = even.next

        odd.next = even_head
        return odd_head
  • 时间复杂度:链表 - 图24
  • 空间复杂度:链表 - 图25

19. Remove Nth Node From End of List

class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        dummy = ListNode(-1, head)
        left, right = dummy, dummy.next

        for _ in range(n):
            right = right.next

        while right:
            left = left.next
            right = right.next

        left.next = left.next.next
        return dummy.next
  • 时间复杂度:链表 - 图26
  • 空间复杂度:链表 - 图27

234. Palindrome Linked List

class Solution:
    def isPalindrome(self, head: ListNode) -> bool:
        if not head or not head.next:
            return True

        slow = fast = head
        l, m = None, head

        # 1.找到链表中点,并反转前半部分
        while fast and fast.next:
            slow = slow.next         # 先移动快慢指针
            fast = fast.next.next

            m.next = l               # 再反转(前半部分)
            l, m = m, slow

        # 2.特判:链表长度为奇数
        if fast:
            m = m.next

        # 3.比较两部分链表
        while l and m:
            if l.val != m.val:
                return False
            l, m = l.next, m.next

        return True
  • 时间复杂度:链表 - 图28
  • 空间复杂度:链表 - 图29

剑指 Offer 35. 复杂链表的复制

class Solution:
    def copyRandomList(self, head: 'Node') -> 'Node':
        if not head:
            return

        dic = dict()                           # Node(old) -> Node(new)

        # 1.复制并将映射关系记录在哈希表
        p = head
        while p:
            dic[p] = Node(p.val)
            p = p.next

        # 2.构建copy节点的next和random指针
        p = head
        while p:
            dic[p].next = dic.get(p.next)      # 使用get(),避免空
            dic[p].random = dic.get(p.random)  # 使用get(),避免空
            p = p.next

        return dic[head]
  • 时间复杂度:链表 - 图30
  • 空间复杂度:链表 - 图31

    class Solution:
      def copyRandomList(self, head: 'Node') -> 'Node':
          if not head:
              return
    
          # 1.复制节点并拼接
          p = head
          while p:
              tmp = Node(p.val)
              p.next, tmp.next = tmp, p.next
              p = p.next.next
    
          # 2.构建random指针
          p = head
          while p:
              if p.random:    # 判空条件
                  p.next.random = p.random.next
              p = p.next.next
    
          # 3.拆分
          copy_head = head.next
          p, q = head, head.next
          while q.next:       # 判空条件
              p.next = p.next.next
              q.next = q.next.next
              p, q = p.next, q.next
    
          # 4.处理原链表尾节点指针
          p.next = None
          return copy_head
    
  • 时间复杂度:链表 - 图32

  • 空间复杂度:链表 - 图33

2. Add Two Numbers

class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        dummy = ListNode(-1)
        p = dummy
        carry = 0

        while l1 or l2:
            num1 = l1.val if l1 else 0
            num2 = l2.val if l2 else 0

            bit_sum = num1 + num2 + carry
            bit = bit_sum % 10 
            carry = bit_sum // 10

            p.next = ListNode(bit)
            p = p.next

            if l1: l1 = l1.next
            if l2: l2 = l2.next

        if carry:
            p.next = ListNode(carry)

        return dummy.next
  • 时间复杂度:链表 - 图34
  • 空间复杂度:链表 - 图35,不考虑返回值的空间占用