Leetcode【86、92、148、206】

  • 2019 年 10 月 29 日
  • 筆記

問題描述:【Linked List】86. Partition List 解題思路:

這道題是給一個鏈表和整數 x,將小於 x 的數按位置順序放在鏈表左側,大於等於 x 的按位置順序放在右側。

類似於快排的劃分過程有木有。可以建立兩個指針 l_end 和 r_end,分別指向 x 的左右兩部分的尾部。再建立一個指針指向當前結點 cur,便於鏈表的遍歷。因為我們不知道第一個結點和 x 的關係,所以可以建一個空結點 node 指向 head,最後 head.next 就是答案。

  • l_end 初始化為 head(空結點),r_end 初始化為 None,cur 指向 head.next 第一個結點;
  • 遍歷 cur: 1、如果 cur.val < x and r_end == None,說明剛開始碰到的都是小於 x 的,就只需要移動 l_end 到 cur 的位置即可; 2、 如果 cur.val < x,這個時候 r_end 不為空,利用這三個指針進行交換和移動即可; 3、否則,碰到的都是大於等於 x 的,就只需要移動 r_end 到 cur 的位置即可。

時間複雜度為 O(n),空間複雜度為 O(1)。

Python3 實現:
# Definition for singly-linked list.  # class ListNode:  #     def __init__(self, x):  #         self.val = x  #         self.next = None    class Solution:      def partition(self, head: ListNode, x: int) -> ListNode:          node = ListNode(-1)  # 頭結點          node.next = head          head = node          l_end, r_end, cur = head, None, head.next          while cur:              if cur.val < x and r_end == None:  # 沒遇到比 x 大的,只移動 l_end                  l_end = cur              elif cur.val < x:  # r_end 不為 None,利用三指針交換                  r_end.next = cur.next  # 交換                  cur.next = l_end.next                  l_end.next = cur                  l_end = cur  # 移動                  cur = r_end              else:                  r_end = cur              cur = cur.next          return head.next

問題描述:【Linked List】92. Reverse Linked List II 解題思路:

這道題是給一個鏈表和區間 [m, n],反轉區間內的數字。

這道題和下面的 Leetcode 206 思路相同。對於一個區間的反轉,需要用 notr 記錄不用反轉區間的最後一個位置;用 start 記錄反轉區間的頭指針;為了反轉方便,再定義 pre 和 cur 分別為前一個指針和當前指針。遍歷 cur,找到反轉區間,進行指針的交換和移動操作即可。

時間複雜度為 O(n),空間複雜度為 O(1)。

Python3 實現:
# Definition for singly-linked list.  # class ListNode:  #     def __init__(self, x):  #         self.val = x  #         self.next = None    class Solution:      def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode:          if not head:              return head          # notr: 不用反轉區間的最後一個位置          # start: 反轉區間的頭指針          # pre, cur:前一個指針和當前指針          notr, start, pre, cur = None, None, None, head          i = 1          while cur:              if i <= m:                  if i == m:  # 初始化四個指針                      notr = pre                      start = cur                  pre = cur                  cur = cur.next              elif m < i <= n:  # 在起始位置的下一個位置反轉,通過指針交換完成                  pre.next = cur.next # 交換                  cur.next = start                  start = cur                  if m == 1:  # 從頭開始                      head = cur                  else:  # 從中間開始                      notr.next = start                  cur = pre.next  # 移動              else:                  break              i += 1          return head

問題描述:【Linked List】148. Sort List 解題思路:

這道題是給一個鏈表,對鏈表排序。要求時間複雜度 O(nlogn),空間複雜度 O(1)。

首先,肯定能想到要麼是使用快速排序,要麼是歸併排序。剛好上面的 Leetcode 86 為鏈表劃分,所以就藉助其思想實現了快排。但是最後一個 case 超時了(嚶嚶嚶),程式碼如下:

Python3 實現:
# Definition for singly-linked list.  # class ListNode:  #     def __init__(self, x):  #         self.val = x  #         self.next = None    class Solution:      def sortList(self, head: ListNode) -> ListNode:          if not head or not head.next:  # 遞歸出口              return head          pivot = head.val          le, ri, cur = head, None, head.next  # 左右區間劃分          while cur:              if cur.val < pivot and ri == None:                  le = cur              elif cur.val < pivot:                  ri.next = cur.next  # 交換                  cur.next = le.next                  le.next = cur                  le = cur  # 移動                  cur = ri              else:                  ri = cur              cur = cur.next          ri = le.next  # 左右兩側排序          le.next = None          lp = self.sortList(head.next)          rp = self.sortList(ri)          if lp == None:   # 將基準 head.val 放到中間              head.next = rp              lp = head          else:              cur = lp              while cur.next:                  cur = cur.next              cur.next = head              head.next = rp          return lp  # 返回鏈表頭結點

看了題解,有人使用歸併排序 mergeSort 通過了,同樣可以做到時間複雜度為 O(nlogn),空間複雜度為 O(1)。程式碼如下(不是我寫的,懶得再寫一次了):

# Definition for singly-linked list.  # class ListNode:  #     def __init__(self, x):  #         self.val = x  #         self.next = None    class Solution:      def sortList(self, head: ListNode) -> ListNode:          if head is None:              return None          p, i = head, 0          while p:              i += 1              p = p.next          return self.mergeSort(head, i)[0]        def mergeSort(self,head,k):          if k == 1:              next = head.next              head.next = None              return head, next          left_head, next = self.mergeSort(head, k//2)          right_head, next = self.mergeSort(next, k-(k//2))          return self.merge(left_head, right_head), next        def merge(self, h1, h2):          dummy = ListNode(0)          p = dummy          while h1 and h2:              if h1.val <= h2.val:                  p.next = h1                  p = p.next                  h1 = h1.next              else:                  p.next = h2                  p = p.next                  h2 = h2.next          if h1 is None and h2 is not None:              p.next = h2          elif h2 is None and h1 is not None:              p.next = h1          return dummy.next

問題描述:【Linked List】206. Reverse Linked List 解題思路:

這道題是給一個鏈表,將鏈表反轉。

鏈表反轉只需要兩個相鄰指針 pre 和 cur 即可。對於 cur 遍歷,先交換(3 次操作)後移動指針到正確的位置,時間複雜度為 O(n)。

Python3 實現:
# Definition for singly-linked list.  # class ListNode:  #     def __init__(self, x):  #         self.val = x  #         self.next = None    class Solution:      def reverseList(self, head: ListNode) -> ListNode:          if not head:              return head          pre, cur = head, head.next          while cur:              pre.next = cur.next  # 交換              cur.next = head              head = cur              cur = pre.next  # 移動          return head

Tags: