hot100-堆

215. 数组中的第k个最大元素

215. 数组中的第K个最大元素 - 力扣(LeetCode)

python 复制代码
class Solution(object):
    def findKthLargest(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        # 就是堆排序的过程:堆排序第一轮以后,会把最大值推到堆顶[0],然后开始下沉到每一个元素正确排序
        # 这里求第k大的数,所以这里的下沉仅仅是往下走k-1个元素,此时的塔尖就是最大的元素
        n = len(nums)
        # 最后一个非叶子节点是n//2-1
        for i in range(n//2-1,-1,-1):
            self.heapify(nums,n,i)
        for i in range(n-1,n-k,-1):
            nums[0],nums[i] = nums[i],nums[0]
            self.heapify(nums,i,0)
        return nums[0]

    def heapify(self,nums,n,i):
        cur = i
        left = 2*i+1
        right = 2*i+2
        if left<n and nums[cur]<nums[left]:
            cur = left
        if right<n and nums[cur]<nums[right]:
            cur = right
        if cur != i:
            nums[i],nums[cur] = nums[cur],nums[i]
            self.heapify(nums,n,cur)

时间复杂度:O(nlogn) # 本质就是堆排序

空间复杂度:O(logn) # 栈空间

利用堆

python 复制代码
class Solution(object):
    def findKthLargest(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        min_heaq = []
        for n in nums:
            heapq.heappush(min_heaq,n)  # 默认最小堆
            if len(min_heaq)>k:
                # 弹掉堆顶最小值
                heapq.heappop(min_heaq)
        return min_heaq[0]

快排

python 复制代码
class Solution(object):
    def findKthLargest(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        # 在快排中,每找到一个基准元素的位置i,则前i个元素都比nums[i]小,后n-i-1个元素比nums[i]大
        # 如果要找第k个最大元素,仅仅令n-i-1=k-1,则此时的基准元素就是我们的目标值
        # 则令i=n-k
        # n-k就是我们的目标下标
        # 如果当前基准元素的下标比我们的目标下标来的小,那么我们就去右区间找,否则就去左区间
        n = len(nums)
        return self.quicksort(nums,0,n-1,n-k)

    def quicksort(self,nums,left,right,target):
        if left==right:
            return nums[left]
        pivot = nums[left]
        i,j = left,right
        while i<j:
            # 找到右侧第一小的元素
            while i<j and nums[j]>=pivot: j-=1
            # 找到左侧第一大的元素
            while i<j and nums[i]<=pivot: i+=1
            if i<j:
                nums[i],nums[j] = nums[j],nums[i]
        # i=j
        nums[left],nums[i] = nums[i],nums[left]
        if i==target:
            return nums[i]
        elif i>target:
            return self.quicksort(nums,left,i-1,target)
        else:
            return self.quicksort(nums,i+1,right,target)

时间复杂度:O(n) # 不是很理解,但是这个在leetcode上时间会超时,必须按照官方的一个特殊的边界条件去写,利用=的判断,写do-while循环,才可以通过全是1的那个示例

空间复杂度:O(logn) # 栈空间

python 复制代码
class Solution(object):
    def findKthLargest(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        # 在快排中,每找到一个基准元素的位置i,则前i个元素都比nums[i]小,后n-i-1个元素比nums[i]大
        # 如果要找第k个最大元素,仅仅令n-i-1=k-1,则此时的基准元素就是我们的目标值
        # 则令i=n-k
        # n-k就是我们的目标下标
        # 如果当前基准元素的下标比我们的目标下标来的小,那么我们就去右区间找,否则就去左区间
        n = len(nums)
        return self.quicksort(nums,0,n-1,n-k)

    def quicksort(self,nums,left,right,target):
        if left==right:
            return nums[left]
        pivot = nums[left]
        i,j = left-1,right+1
        while i<j:
            # 找到右侧第一小的元素
            j-=1
            while i<j and nums[j]>pivot: j-=1
            # 找到左侧第一大的元素
            i+=1
            while i<j and nums[i]<pivot: i+=1
            if i<j:
                nums[i],nums[j] = nums[j],nums[i]
        # Hoare 划分的核心差异:结束时,数组被切分为 [left, j] 和 [j+1, right]
        # 注意:这里 j 这个位置上的元素不一定恰好就是 pivot,但它完美地划清了界限!
        if j>=target:
            return self.quicksort(nums,left,j,target)
        else:
            return self.quicksort(nums,j+1,right,target)

347. 前k个高频元素

347. 前 K 个高频元素 - 力扣(LeetCode)

python 复制代码
class Solution(object):
    def topKFrequent(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        # 简单思路:先求出频率字典,然后排序,取k个
        # 如果直接使用sorted,那么其实本质用的是快排,所以时间复杂度就是nlog(n)
        d = {}
        for i in nums:
            d[i] = d.get(i,0)+1
        d_list = sorted(d.items(),key = lambda x:x[1],reverse = True)
        res = []
        for i in range(k):
            res.append(d_list[i][0])
        return res

时间复杂度:O(nlogn)

空间复杂度:O(n)

但是其实没必要存储所有的元素,我们仅仅需要存储前k个高频元素,利用堆的思想。

python 复制代码
class Solution(object):
    def topKFrequent(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        d = {}
        for i in nums:
            d[i] = d.get(i,0)+1
        min_heaq = []
        for key,value in d.items():
            heapq.heappush(min_heaq,(value,key))  # 按照频率排序
            if len(min_heaq)>k:
                heapq.heappop(min_heaq)
        res = [0]*k
        # 按照高频到低频排序
        for i in range(k-1,-1,-1):
            res[i] = heapq.heappop(min_heaq)[1]
        return res

时间复杂度:O(nlogn)

空间复杂度:O(n) # 因为字典还是需要O(n),heapq需要O(k)

295. 数据流的中位数

295. 数据流的中位数 - 力扣(LeetCode)

python 复制代码
class MedianFinder(object):
    # 其实维护两个堆就可以
    # 一个存小于等于中位数的元素【大顶堆】【默认是小顶堆,所以存负数】
    # 一个存大于中位数的元素【小顶堆】【上面的比下面的元素个数最多多1】
    def __init__(self):
        self.min_heaq=[]
        self.max_heaq=[]

    def addNum(self, num):
        """
        :type num: int
        :rtype: None
        """
        if not self.min_heaq or num<=-self.min_heaq[0]:
            heapq.heappush(self.min_heaq,-num)
            if len(self.min_heaq)>len(self.max_heaq)+1:
                heapq.heappush(self.max_heaq,-heapq.heappop(self.min_heaq))
        else:
            heapq.heappush(self.max_heaq,num)
            if len(self.min_heaq)<len(self.max_heaq):
                heapq.heappush(self.min_heaq,-heapq.heappop(self.max_heaq))

    def findMedian(self):
        """
        :rtype: float
        """
        if len(self.min_heaq)==len(self.max_heaq):
            return (-self.min_heaq[0]+self.max_heaq[0])/2.0
        else:
            return -self.min_heaq[0]

时间复杂度:

  • addNum: O(logn) # n 为累计添加的数的数量,每增加一个元素,仅仅调整一次堆,所以是logn
  • findMedian: O(1)

空间复杂度:O(n) # 两个堆的开销

相关推荐
小小小米粒1 小时前
函数式接口 + Lambda = 方法逻辑的 “插拔式解耦”
开发语言·python·算法
风吹乱了我的头发~2 小时前
Day31:2026年2月21日打卡
开发语言·c++·算法
望舒5132 小时前
代码随想录day33,动态规划part2
java·算法·leetcode·动态规划
那起舞的日子2 小时前
牛客网刷算法的启发
算法
追随者永远是胜利者3 小时前
(LeetCode-Hot100)169. 多数元素
java·算法·leetcode·go
s砚山s3 小时前
代码随想录刷题——二叉树篇(二十)
算法
Dr.Kun3 小时前
【鲲码园PsychoPy】延迟折扣任务(DDT)
python·psychopy·心理学编程
coding者在努力3 小时前
LangChain简介,最直白的介绍
人工智能·python·语言模型·langchain
癫狂的兔子4 小时前
【Python】【机器学习】支持向量积
python·机器学习