912. Sort an Array

  1. class Solution:
  2. def sortArray(self, nums: List[int]) -> List[int]:
  3. def partition(arr, low, high): # 将pivot放置于最终排序位置,并返回index
  4. idx_pivot = random.randint(low, high) # [low, high]
  5. arr[low], arr[idx_pivot] = arr[idx_pivot], arr[low]
  6. pivot = arr[low]
  7. left, right = low, high
  8. while left < right:
  9. while left < right and arr[right] >= pivot:
  10. right -= 1
  11. arr[left] = arr[right]
  12. while left < right and arr[left] <= pivot:
  13. left += 1
  14. arr[right] = arr[left]
  15. arr[left] = pivot
  16. return left
  17. def quick_sort(arr, low, high):
  18. if low >= high:
  19. return
  20. mid = partition(arr, low, high)
  21. quick_sort(arr, low, mid - 1)
  22. quick_sort(arr, mid + 1, high)
  23. quick_sort(nums, 0, len(nums) - 1)
  24. return nums
  1. class Solution:
  2. def sortArray(self, nums: List[int]) -> List[int]:
  3. def merge_sort(arr, low, high):
  4. if low >= high:
  5. return
  6. mid = low + high >> 1
  7. merge_sort(arr, low, mid) # [low, mid]
  8. merge_sort(arr, mid + 1, high) # [mid+1, high]
  9. tmp = [] # 暂存[low, high]排序结果
  10. left, right = low, mid + 1
  11. while left <= mid and right <= high:
  12. if arr[left] < arr[right]:
  13. tmp.append(arr[left])
  14. left += 1
  15. else:
  16. tmp.append(arr[right])
  17. right += 1
  18. tmp += arr[left:mid+1] # 还剩余一部分(已经有序)
  19. tmp += arr[right:high+1]
  20. arr[low:high+1] = tmp # 暂存的有序部分覆盖掉原数组
  21. merge_sort(nums, 0, len(nums) - 1)
  22. return nums
  1. class Solution:
  2. def sortArray(self, nums: List[int]) -> List[int]:
  3. n = len(nums)
  4. nums = [0] + nums # 1-index:左孩子 2*i
  5. # 右孩子 2*i + 1
  6. def max_heapify(arr, i, end):
  7. j = 2 * i # 左孩子
  8. while j <= end:
  9. if j+1 <= end and arr[j+1] > arr[j]: # 选择左、右孩子中较大的一个
  10. j += 1
  11. if arr[i] < arr[j]:
  12. arr[i], arr[j] = arr[j], arr[i]
  13. i = j # 往下继续调整
  14. j = 2 * i
  15. else:
  16. break
  17. for i in range(n//2, 0, -1): # 从首个非叶子节点开始调整(n//2)
  18. max_heapify(nums, i, n)
  19. for j in range(n, 0, -1): # 堆排序
  20. nums[1], nums[j] = nums[j], nums[1] # 堆顶与堆底元素互换
  21. max_heapify(nums, 1, j-1) # 重新调整堆
  22. return nums[1:] # 删除首个占位元素

215. Kth Largest Element in an Array

  1. class Solution:
  2. def findKthLargest(self, nums: List[int], k: int) -> int:
  3. max_heap = [-num for num in nums]
  4. heapq.heapify(max_heap)
  5. for _ in range(k - 1):
  6. heapq.heappop(max_heap)
  7. return -max_heap[0]
  1. class Solution:
  2. def findKthLargest(self, nums: List[int], k: int) -> int:
  3. min_heap = []
  4. for num in nums:
  5. heapq.heappush(min_heap, num)
  6. if len(min_heap) > k:
  7. heapq.heappop(min_heap)
  8. return min_heap[0]
  1. class Solution:
  2. def findKthLargest(self, nums: List[int], k: int) -> int:
  3. def partition(arr, low, high):
  4. idx_pivot = random.randint(low, high)
  5. arr[low], arr[idx_pivot] = arr[idx_pivot], arr[low]
  6. pivot = arr[low]
  7. left, right = low, high
  8. while left < right:
  9. while left < right and arr[right] >= pivot:
  10. right -= 1
  11. arr[left] = arr[right]
  12. while left < right and arr[left] <= pivot:
  13. left += 1
  14. arr[right] = arr[left]
  15. arr[left] = pivot
  16. return left
  17. def quick_sort(arr, low, high):
  18. if low >= high:
  19. return
  20. mid = partition(arr, low, high)
  21. if mid < (idx_k := len(arr)-k):
  22. quick_sort(arr, mid+1, high)
  23. elif mid > idx_k:
  24. quick_sort(arr, low, mid-1)
  25. else:
  26. return
  27. quick_sort(nums, 0, len(nums)-1)
  28. return nums[-k]
  • 时间复杂度:排序 - 图1,即为快速排序划分枢轴的最差复杂度。即每次都划分为排序 - 图2排序 - 图3的区间。
  • 空间复杂度:排序 - 图4

剑指 Offer 40. 最小的k个数

148. Sort List

8c47e58b6247676f3ef14e617a4686bc258cc573e36fcf67c1b0712fa7ed1699-Picture2.png

  1. class Solution:
  2. def merge_two_lists(self, list1, list2):
  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
  15. def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
  16. if not head or not head.next:
  17. return head
  18. slow, fast = head, head.next
  19. while fast and fast.next:
  20. slow = slow.next
  21. fast = fast.next.next
  22. mid = slow.next
  23. slow.next = None # cut,断链
  24. l1 = self.sortList(head)
  25. l2 = self.sortList(mid)
  26. return self.merge_two_lists(l1, l2) # merge,合并
  • 时间复杂度:排序 - 图6
  • 空间复杂度:排序 - 图7

c1d5347aa56648afdec22372ee0ed13cf4c25347bd2bb9727b09327ce04360c2-Picture1.png

  1. class Solution:
  2. def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
  3. if not head:
  4. return
  5. length_list = 0 # 链表长度
  6. p = head
  7. while p:
  8. p = p.next
  9. length_list += 1
  10. dummy = ListNode(-1, head)
  11. base = 1 # 每次归并的子链表长度
  12. while base < length_list:
  13. pre, h = dummy, dummy.next
  14. while h:
  15. h1, i = h, base # 归并链表 1
  16. while h and i:
  17. h = h.next
  18. i -= 1
  19. if i: # 剩余长度不足base(已经有序)
  20. break
  21. h2, i = h, base # 归并链表 2
  22. while h and i:
  23. h = h.next
  24. i -= 1
  25. len1, len2 = base, base - i
  26. while len1 and len2: # 迭代合并
  27. if h1.val < h2.val:
  28. pre.next = h1
  29. h1 = h1.next
  30. len1 -= 1
  31. else:
  32. pre.next = h2
  33. h2 = h2.next
  34. len2 -= 1
  35. pre = pre.next
  36. pre.next = h1 if len1 else h2
  37. while len1 > 0 or len2 > 0: # 将pre指针移动到归并链表尾部(必须指定>0)
  38. pre = pre.next
  39. len1, len2 = len1 - 1, len2 - 1
  40. pre.next = h
  41. base *= 2
  42. return dummy.next
  • 时间复杂度:排序 - 图9
  • 空间复杂度:排序 - 图10

剑指 Offer 51. 数组中的逆序对

class Solution:
    def reversePairs(self, nums: List[int]) -> int:

        def merge_sort(arr, low, high):
            if low >= high:
                return 0

            mid = low + high >> 1
            inversed_pairs = merge_sort(arr, low, mid) + merge_sort(arr, mid + 1, high)

            tmp = []
            left, right = low, mid + 1

            while left <= mid and right <= high:
                if arr[left] <= arr[right]:           # 元素相同,必须先添加左半部分 
                    tmp.append(arr[left])
                    left += 1
                else:                                 # 右半部分较小时,添加逆序对数
                    tmp.append(arr[right])
                    right += 1
                    inversed_pairs += mid - left + 1

            tmp += arr[left:mid+1]                    # 剩余一部分无须计算逆序对
            tmp += arr[right:high+1]

            arr[low:high+1] = tmp
            return inversed_pairs

        return merge_sort(nums, 0, len(nums) - 1)
  • 时间复杂度:排序 - 图11
  • 空间复杂度:排序 - 图12,临时数组空间

347. Top K Frequent Elements

179. Largest Number

对于排序 - 图13中的任意两个值排序 - 图14排序 - 图15,我们无法直接从常规角度上确定其大小/先后关系。
但我们可以根据「结果」来决定排序 - 图16排序 - 图17的排序关系:
如果拼接结果 排序 - 图18 要比排序 - 图19好,那么我们会认为排序 - 图20应该放在排序 - 图21前面。
另外,注意我们需要处理前导零(最多保留一位)。

from functools import cmp_to_key

class Solution:
    def largestNumber(self, nums: List[int]) -> str:
        strs = list(map(str, nums))

        # 自定义排序规则
        def cmp(a: str, b: str):
            if a + b == b + a:
                return 0
            elif a + b > b + a:
                return 1
            else:
                return -1

        strs.sort(key=cmp_to_key(cmp), reverse=True)
        # 注意前导0的特判
        return ''.join(strs) if strs[0] != '0' else '0'