2. 排序算法

时间复杂度

排序法 最坏情况 平均时间 稳定度 辅助存储
冒泡排序 O(n^2) O(n^2) 稳定 O(1)
插入排序 O(n^2) O(n^2) 稳定 O(1)
选择排序 O(n2) O(n^2) 稳定 O(1)
快速排序 O(n^2) O(n*log2n) 不稳定 O(logn)
堆排序 O(n*log2n) O(n*log2n) 不稳定 O(1)
归并排序 O(n*log2n) O(n*log2n) 不稳定 O(1)
  • 待排序列正序时,直接插入排序的时间复杂度为O(n)
  • 希尔排序的时间复杂度为O(n^3/2)
  • 堆排序时间复杂度分析
    • 最后我们简要分析下堆排序的时间复杂度。建堆的时间复杂度是O(n),我们在每次重新调整堆时,都要将父节点与孩子节点比较,这样,每次重新调整堆的时间复杂度变为O(logn),而堆排序时有n-1次重新调整堆的操作,建堆时有((len-1)/2+1)次重新调整堆的操作,因此堆排序的平均时间复杂度为\(O(n*logn)\)。由于我们这里没有借用辅助存储空间,因此空间复杂度为O(1)。
    • 堆排序在排序元素较少时有点大材小用,待排序列元素较多时,堆排序还是很有效的。另外,堆排序在最坏情况下,时间复杂度也为O(nlogn)。相对于快速排序(平均时间复杂度为O(nlogn),最坏情况下为\(O(n*n)\)),这是堆排序的最大优点。

实现

排序题目 java版本

快排

import random
from typing import List


class QuickSortMethod:
    def quick_sort(self, nums):
        self.quick_sort_help(nums, 0, len(nums) - 1)
        return nums

    def quick_sort_help(self, nums, left, right):
        if left >= right:
            return nums
        if left < right:
            idx = random.randint(left, right)
            pivot = nums[idx]
            nums[idx], nums[left] = nums[left], nums[idx]
            i = left
            j = right
            while i < j:
                while i < j and nums[j] > pivot:
                    j -= 1
                nums[i] = nums[j]
                while i < j and nums[i] <= pivot:
                    i += 1
                nums[j] = nums[i]
            nums[i] = pivot
            self.quick_sort_help(nums, left, i - 1)
            self.quick_sort_help(nums, i + 1, right)
        return nums

归并排序

class MergeSolution:
    def merge_sort(self, nums, l, r):
        if l == r:
            return
        mid = (l + r) // 2
        self.merge_sort(nums, l, mid)
        self.merge_sort(nums, mid + 1, r)
        tmp = []
        i, j = l, mid + 1
        while i <= mid or j <= r:
            if i > mid or (j <= r and nums[j] < nums[i]):
                tmp.append(nums[j])
                j += 1
            else:
                tmp.append(nums[i])
                i += 1
        nums[l: r + 1] = tmp

    def sortArray(self, nums: List[int]) -> List[int]:
        self.merge_sort(nums, 0, len(nums) - 1)
        return nums

堆排序

class HeapSort:
    def sortArray(self, nums):
        self.heap_sort(nums)
        return nums

    def heap_sort(self, nums):
        self.heap_init(nums)
        for i in range(len(nums) - 1, -1, -1):
            nums[i], nums[0] = nums[0], nums[i]
            self.adjust_heap_down(nums, i - 1, 0)

    def heap_init(self, nums):
        n = len(nums) - 1
        for i in range(n, -1, -1):
            self.adjust_heap_down(nums, n, i)

    def adjust_heap_down(self, nums, heap_size, idx):
        left = 2 * idx + 1
        while left <= heap_size:
            child_idx = left
            right = left + 1
            if right <= heap_size and nums[right] > nums[left]:
                child_idx = right
            if nums[child_idx] <= nums[idx]:
                break
            nums[idx], nums[child_idx] = nums[child_idx], nums[idx]
            idx = child_idx
            left = 2 * idx + 1

前K个高频元素

力扣
维护一个小顶堆,存放出现频率最高的k个元素。

from collections import Counter
class Solution2:
    def topKFrequent(self, nums: List[int], k: int) -> List[int]:
        def site_up(arr, idx):
            parent = (idx - 1) // 2
            while parent >= 0:
                if arr[parent][1] > arr[idx][1]:
                    arr[idx], arr[parent] = arr[parent], arr[idx]
                    idx = parent
                    parent = (idx - 1) // 2
                else:
                    break

        def site_down(arr, idx, size):
            left_child = idx * 2 + 1
            while left_child <= size:
                child = left_child
                right_child = left_child + 1
                if right_child <= size and arr[right_child][1] < arr[left_child][1]:
                    child = right_child
                if arr[child][1] < arr[idx][1]:
                    arr[idx], arr[child] = arr[child], arr[idx]
                    idx = child
                    left_child = 2 * idx + 1
                else:
                    break
		# counter 统计出现次数,然后转为list,对其遍历
        stat = Counter(nums)
        stat = list(stat.items())
        heap = []
        for i in range(k):
            heap.append(stat[i])
            site_up(arr=heap, idx=len(heap) - 1)

        for i in range(k, len(stat)):
            if stat[i][1] > heap[0][1]:
                heap[0] = stat[i]
                site_down(heap, 0, k - 1)

        return [item[0] for item in heap[:k]]

根据字符出现频率排序

力扣 451

class Solution3:
    def frequencySort(self, s: str) -> str:
        c = Counter(s)
		# 对字典排序
        res = dict(sorted(c.items(), key=lambda x: -x[1]))
        return ''.join(k * v for k, v in res.items())

荷兰国旗问题

力扣 75

class Solution:
    def sortColors(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        zero = -1
        one = 0
        two = len(nums)
        while one < two:
            if nums[one] == 0:
                zero += 1
                nums[zero], nums[one] = nums[one], nums[zero]
                one += 1
            elif nums[one] == 2:
                two -= 1
                nums[one], nums[two] = nums[two], nums[one]
            else:
                one += 1
        return nums
import collections
import heapq


class Solution4:
    def isPossible(self, nums: List[int]) -> bool:
        mp = collections.defaultdict(list)
        print(mp)
        for x in nums:
            print("mp:", mp.items())
            if mp.get(x - 1):
                queue = mp.get(x - 1)
                prevLength = heapq.heappop(queue)
                heapq.heappush(mp[x], prevLength + 1)
            else:
                heapq.heappush(mp[x], 1)

        return not any(queue and queue[0] < 3 for queue in mp.values())


if __name__ == "__main__":
    s = Solution4()
    # nums = [5, -3, 9, 1, 7, 7, 9, 10, 2, 2, 10, 10, 3, -1, 3, 7, -9, -1, 3, 3]
    # k = 3
    s.isPossible([1, 2, 3, 3, 4, 4, 5, 5])
posted @ 2021-12-16 14:31  _无支祁  阅读(42)  评论(0)    收藏  举报