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) # 两个堆的开销

相关推荐
宿州派大星2 小时前
Python实战:PyQt5 + OpenCV + Dlib 打造AI桌面应用
人工智能·python·qt
碧海银沙音频科技研究院3 小时前
炬芯ATS3089X手表的HFP通话不自动路由到设备BT的问题解决
网络·人工智能·嵌入式硬件·算法
承渊政道3 小时前
【从零开始大模型开发与微调:基于PyTorch与ChatGLM】(开源大模型ChatGLM高级定制化应用实战)
人工智能·pytorch·python·llm·模型微调·glm
mmmmath_38 小时前
LeetCode.199.二叉树的右视图
数据结构·leetcode
专注仿真8 小时前
引擎扩展性与集成设计深度剖析:从 14 个扩展点到 DIS→HLA 演进之路
开发语言·算法·仿真引擎·推演引擎
码爸8 小时前
支持向量机介绍与示例
算法·机器学习·支持向量机
怕浪猫8 小时前
2028编程圈很火的10个Skills
算法·面试·github
Smoothcloud润云9 小时前
PyTorch大模型权重加载与启动耗时优化实战:定位磁盘、内存与显存瓶颈
人工智能·pytorch·python·深度学习·gpu算力
databook9 小时前
从循环到向量化:NumPy提速的7个关键思维
python·数据分析·numpy