leetcode 912 排序数组 堆排序

不停把当前最大值扔到数组最右边

java 复制代码
开始:[17 3 2 1 100 36 19 25 7]
建堆后:[100 ... ... ...]
第一轮:[堆区域........][100]
第二轮:[堆区域......][36][100]
第三轮:[堆区域....][25][36][100]
最终:[1][2][3][7][17][19][25][36][100]

数组长度为n

阶段一:建堆(Build Heap)

这个阶段的目标是把一个无序的数组,调整成一个"最大堆"。

从最后一个非叶子节点开始:这个节点的位置是 n/2 - 1 (n 是数组长度)。视频中的例子,数组长度n= 9,所以从索引 3 开始。 自底向上调整:**从右到左,从下到上,依次调用 heapify 函数,**确保每个子树都满足最大堆的性质。 核心 heapify 操作:比较父节点和它左右子节点的值,如果父节点不是最大的,就把它和最大的子节点交换。然后,递归地对被交换的子节点进行 heapify 。

阶段二:排序(Sort)

建好最大堆后,数组的第一个元素(索引 0)(树顶)就是当前的最大值。

交换:将堆顶元素(最大值)与数组的最后一个元素交换。 缩小堆范围:将堆的大小减 1(相当于把最大的那个数移出堆,放在数组末尾)。 (不再调整数据末尾的数)

重新调整:对新的堆顶元素(索引 0)调用 heapify ,把剩下的 n-1 个元素重新调整成最大堆。

重复:不断重复"交换"和"调整"的过程,直到堆里只剩一个元素。此时,整个数组就排好序了。

python 复制代码
class Solution:
    def sortArray(self, nums: List[int]) -> List[int]:

        # 传入i后,自i向下递归,沉下最小的
        def heap(n,i):
            big = i
            left = 2*i+1
            right = 2*i+2

            # 找到三个节点中最大的那个
            if left<n and nums[big] < nums[left]:
                big = left   # big在不断更新
            if right<n and nums[big] < nums[right]:
                big = right

            if big != i:
                nums[i],nums[big] = nums[big],nums[i]
                # i如果不是最大值,交换后节点i被扔到子节点的位置,此时的largest是原来的left/right位置(i的下一层)
                heap(n, big)  #传入i的下一层,递归

        n = len(nums)
      # 1. 构建最大堆:从数组最后一个非叶子节点(索引为n//2-1)(即树的倒数第二层)开始,从下往上,从右往左,一直到根节点
        # 从下往上,构建最大堆,从下往上把最大值上浮 
        for i in range(n//2-1, -1, -1):
            heap(n, i)
            
        # 此时:最大值一定在堆顶

        # 2. 排序:逐个将堆顶元素(最大值)与数组的最后一个元素交换。 缩小堆范围:将堆的大小减 1
        # 把最大值放到最后,再排一次,排完最大值又在堆顶,然后以后不参与排序,
        # end 从右往左移动,表示堆的有效范围不断缩小
        for end in range(n - 1, 0, -1):
            nums[0], nums[end] = nums[end], nums[0]
            heap(end, 0)

        return nums         
        
  • 时间复杂度:O(n log n)。建堆是 O(n),排序阶段需要 n 次 O(log n) 的调整。
  • 空间复杂度:O(1)。因为所有操作都在原数组上进行,是一种原地排序。
相关推荐
6Hzlia14 分钟前
【Classic 150 刷题计划】 LeetCode 14. 最长公共前缀 | C++ 纵向扫描法与防越界细节
c++·算法·leetcode
Tisfy16 小时前
LeetCode 0836.矩形重叠:xy两方向分别看
数学·leetcode·题解·模拟
青山木17 小时前
Hot 100 --- 最长递增子序列
java·数据结构·算法·leetcode·动态规划
土司大王18 小时前
LeetCode hot100——33.搜索旋转排序数组:Java 二分模板与 O(log n) 实现
数据结构·算法·leetcode
辰辉创聚18 小时前
禽流感病毒分子基础:表面抗原与内部转录复合体的功能解析
ide·leetcode·rabbitmq·重组血凝素蛋白·甲型流感病毒核蛋白·禽流感单抗
ysu_031420 小时前
08-二叉树遍历:四种方式详解
c语言·数据结构·算法·leetcode
土司大王20 小时前
LeetCode hot100——153.寻找旋转排序数组中的最小值:Java 二分模板与 O(log n) 分析
java·算法·leetcode
土司大王21 小时前
LeetCode hot100——4.寻找两个正序数组的中位数:Java 二分第K小 递归裁剪
java·算法·leetcode
6Hzlia1 天前
【Classic 150 刷题计划】 LeetCode 123. 买卖股票的最佳时机 III | C++ 状态机动态规划与通用交易拓展
c++·算法·leetcode