数据结构与算法----学习笔记(8)堆实战

两个概念

  • 元组
  • 模拟大顶堆
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述在这里插入图片描述


1046.最后一块石头的重量

class Solution:
    def lastStoneWeight(self, stones: List[int]) -> int:

        # 将所有数取反,模拟小顶堆
        heap = [-stone for stone in stones]
        # 对数组构造小顶堆
        heapq.heapify(heap)
        while len(heap)>1:
            x = heapq.heappop(heap)
            y = heapq.heappop(heap)
            # 如果最重的两个大小不一样,那么将差值加入
            if x!=y:
                heapq.heappush(heap,x-y)
        
        if heap:return -heap[0]
        return 0

三个技巧

在这里插入图片描述
固定一个大小为K的大顶堆,新加入的数和堆顶的数作比较,将较大的一个移除,那么最后剩下的就是最小的k个数,其中堆顶的数就是第K个小的数
固定一个大小为K的小顶堆,最后一个出堆的数就是第K小的数

295.数据流的中位数

class MedianFinder:

    def __init__(self):
        self.count = 0
        self.max_heap = []
        self.min_heap = []

    def addNum(self, num: int) -> None:
        self.count +=1
        # 将num压入最大堆,由于Python中只有小顶堆,因此用一个负号去模拟小顶堆,因此用元组的形式
        heapq.heappush(self.max_heap,(-num,num))
        _,max_heap_top = heapq.heappop(self.max_heap)
        heapq.heappush(self.min_heap,max_heap_top)
        if self.count&1:
            min_heap_top = heapq.heappop(self.min_heap)
            heapq.heappush(self.max_heap,(-min_heap_top,min_heap_top))



    def findMedian(self) -> float:
        if self.count&1:
            # 0 是指大顶堆的第一个数  1 是元组中的正数
            return self.max_heap[0][1]
        else:
            return (self.max_heap[0][1] + self.min_heap[0])/2


1439.有序矩阵中的第 k 个最小数组和

class Solution:
    def kthSmallest(self, mat: List[List[int]], k: int) -> int:
        h = []
        # 先初始化矩阵每一行的第一个数之和   以及指针的初始位置
        cur = ( sum(vec[0] for  vec in mat), tuple( [0] * len(mat) ))
        heapq.heappush(h,cur)
        # 通过集合,排除重复使用
        seen = set(cur)

        for _ in range(k):
            acc,pointers = heapq.heappop(h)
            # 对于指针进行每个指针的遍历
            for i,pointer in enumerate(pointers):
                # 如果指正还没到最后一个位置
                if pointer != len(mat[0])-1:

                    t = list(pointers)
                    t[i] = pointer +1
                    tt = tuple(t)
                    if tt not in seen:
                        seen.add(tt)

                        heapq.heappush(h, (acc+mat[i][pointer+1] - mat[i][pointer],tt) )
        return acc 

264.丑数 II
在这里插入图片描述

class Solution:
    def nthUglyNumber(self, n: int) -> int:
        nums = [2,3,5]
        explored = {1}
        pq = [1]
        for i in range(1,n+1):
            x = heapq.heappop(pq)
            if i == n:
                return x
            for num in nums:
                t = x *num 
                if t not in explored:
                    explored.add(t)
                    heapq.heappush(pq,t)
        return -1

在这里插入图片描述

class Solution:
    def nthUglyNumber(self, n: int) -> int:
        ans = [0] * (n+1)
        ans [1] = 1
        i2 = 1
        i3 = 1
        i5 = 1

        idx = 2
        while idx<=n:
            a = ans[i2]*2
            b = ans[i3]*3
            c = ans[i5]*5

            m = min(a,b,c)
            if m ==a :
                i2 +=1
            if m == b:
                i3 +=1
            if m ==c :
                i5 +=1
            
            ans[idx] = m
            idx +=1
        return ans[n]

在这里插入图片描述

871.最低加油次数

class Solution:
    def minRefuelStops(self, target: int, startFuel: int, stations: List[List[int]]) -> int:
        stations +=[(target,0)]
        cur = startFuel
        ans = 0

        last = 0
        h = []
        # 该加油站距离起点的距离和该加油站有多少油
        for i ,fuel in stations:
            cur -= (i-last)# 从上一个加油站到这一个加油站距离多远
            while cur<0 and h:
                cur -= heapq.heappop(h)     # 就应该在上一个加油站加油,因为模拟小顶堆,因此用-
                ans+=1
            
            if cur<0:
                return -1
            heappush(h,-fuel)
            last = i
        return ans

1642.可以到达的最远建筑

class Solution:
    def furthestBuilding(self, heights: List[int], bricks: int, ladders: int) -> int:
        h = []
        for i in range(1,len(heights)):
            diff = heights[i] - heights[i-1]
            # 两层的差值小于0,则继续
            if diff<=0:
                continue
            # 如果差值大于0,并且砖头不够,但是有一个梯子
            if bricks <diff and ladders>0:
                ladders -=1 # 用一把梯子
                # 如果之前的最大差值大于先在的差值,那么就应该在之前用梯子,从而节约砖头
                if h and -h[0]>diff:
                    # 先查看一下,满足了才pop出第一个
                    bricks -= heapq.heappop(h)
                # 如果不满足上述条件,则这一次就是用梯子,
                else:
                    continue
            bricks -=diff
            if bricks<0:
                return i-1
            heapq.heappush(h,-diff)
        return len(heights) -1
                

总结

理解什么时候使用最大堆、什么时候使用最小堆
最大堆求解什么问题、最小堆求解什么问题

堆的中心动态求极值
最大值(大顶堆),最小值(小顶堆),主要核心是动态,如果不是动态其实没必要使用堆
分析题目是动态是难点

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值