排序

比较排序

HeapSort

  • 第一步:O(N)建立最大堆

  • 第二步:不停地从最大堆中pop出根,in-place的话只需要O(N)的空间

class Solution:
    def heapify(self, nums, n, i):
        # heapify nums[:n] by sinking nums[i] to correct place
        largest = i
        l, r = 2*i+1, 2*i+2
        if l<n and nums[i]<nums[l]:
            largest = l
        if r<n and nums[largest]<nums[r]:
            largest = r
        if largest != i:
            nums[i], nums[largest] = nums[largest], nums[i]
            self.heapify(nums, n, largest)
    
    def sortArray(self, nums: List[int]) -> List[int]:
        n = len(nums)
        for i in range(n>>1, -1, -1):
            self.heapify(nums, n, i)
        
        for i in range(n-1, 0, -1):
            nums[i], nums[0] = nums[0], nums[i]
            self.heapify(nums, i, 0)
        return nums

# 偷懒写法:需要O(N)额外的空间
class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        heapq.heapify(nums)
        res = []
        while nums:
            res.append(heapq.heappop(nums))
        return res

MergeSort

class Solution:
    def merge(self, nums1, nums2):
        m, n = len(nums1), len(nums2)
        res = [None for _ in range(m+n)]
        i = j = k = 0
        while i<m and j<n:
            n1, n2 = nums1[i], nums2[j]
            res[k] = min(n1, n2)
            k += 1
            if n1<n2:
                i += 1
            else:
                j += 1
        res[k:] = nums1[i:] if i<m else nums2[j:]
        return res
    
    def sortArray(self, nums: List[int]) -> List[int]:
        if len(nums) <= 1: return nums
        m = len(nums) >> 1
        return self.merge(self.sortArray(nums[:m]),
                          self.sortArray(nums[m:]))

QuickSort

  • 自上而下的分治,没有divide & conquer之后的combine那一步

  • 如果每一次partition都拿到最大的一个数,那么最坏的时间复杂度是O(N²)。平均复杂度一般为O(N),而且用随机选择pivot的partition能够摊平时间复杂度。

class Solution:
    def swap(self, nums, i, j):
        nums[i], nums[j] = nums[j], nums[i]
    
    def partition(self, nums, l, r):
        pivot = nums[l]
        j = l
        for i in range(l+1, r+1):
            if nums[i] < pivot:
                j += 1
                self.swap(nums, i, j)
        self.swap(nums, l, j)
        return j
    
    def sortArray(self, nums, l=0, r=None):
        if r==None: r = len(nums)-1
        if l<r:
            p = self.partition(nums, l, r)
            self.sortArray(nums, l, p-1)
            self.sortArray(nums, p+1, r)
        return nums

线性时间排序

Counting Sort

假设已知数据的所有可能

  • 第一步:统计每个数字对应的cumulative count,即最后结果应该在的位置i.e. rank

  • 第二步:在每一个rank的位置填入数字

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        def index(i): return i-minval

        minval, maxval = min(nums), max(nums)
        c = [0 for _ in range(minval, maxval+1)]
        for n in nums:
            c[index(n)] += 1
        for i in range(1, len(c)):
            c[i] += c[i-1]

        res = [None for _ in range(len(nums))]
        for n in nums:
            res[c[index(n)]-1] = n
            c[index(n)] -= 1
        return res

BucketSort

假设数据的范围,而且分布是均匀的,可以用桶排序。这里选择的数据范围根据例题

class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:
        OFFSET = 50000
        STEP = 1000
        
        n = len(nums)
        for i in range(n):
            nums[i] += OFFSET
        
        nBuckets = max(nums) // STEP
        buckets = [[] for _ in range(nBuckets+1)]
        for n in nums:
            index = n // STEP
            buckets[index].append(n)
        
        for b in buckets:
            b.sort()
        
        return [x-OFFSET for b in buckets for x in b]

Last updated

Was this helpful?