当前位置: 首页 > news >正文

算法 之 堆

文章目录

  • 基础
    • 1046.最后一块石头的重量
    • 3264.K次乘运算后的最终数组I
    • 选出和最大的K个元素
    • 2406.将区间分为最少组数
  • 重排元素
    • [模版题] 767.重构字符串
    • 1054.距离相等的条形码
  • 第K大/小元素
  • 反悔堆
    • LCP.30魔塔游戏

  • 堆的好处,每次弹出和装入堆,时间复杂度都是 logn
  • 支持多个优先级排序,只要你的元素是元组,那么第一个优先级就是 第一个元素,第二个优先级就是 第二个元素,以此类推
  • 堆:分为小堆和大堆,但是python中只有小堆的用法,也就是heapq只能支持小堆,如果想用大堆,将元素全部取反即可
  • 基本操作:
import heapq
# 默认是小堆
hea = []
# 弹出并返回堆中的最小值,如果堆为空,则不允许弹出
heapq.heappop(hea)
# 往堆中加入元素,并维护为小堆
num = 1
heapq.heappush(hea,num)
# 这里比价好玩的是,判断堆是否为空,其实我们只用判断len(hea)是否等于0

基础

1046.最后一块石头的重量

1046.最后一块石头的重量

在这里插入图片描述

  • 使用的是大堆,所以要把元素取反
import heapq
class Solution:
    def lastStoneWeight(self, stones: List[int]) -> int:
        # 经典的堆的问题
        # 但是这个是小根堆,得转化为负数才行
        hea = []
        for i in stones:
            heapq.heappush(hea,-i)
        while len(hea) > 1:
            y = -heapq.heappop(hea)
            x = -heapq.heappop(hea)
            if x == y :
                continue
            else:
                heappush(hea,x-y)
        print(len(hea))
        if len(hea) == 0:
            return 0
        else:
            return -heappop(hea)

3264.K次乘运算后的最终数组I

3264.K次乘运算后的最终数组I

在这里插入图片描述

  • 入堆的元素,(nums[i],i),也就是要记录这个下标
import heapq
class Solution:
    def getFinalState(self, nums: List[int], k: int, multiplier: int) -> List[int]:
        # 找最小值的类型
        # 并且还是有顺序的
        n = len(nums)
        hea = []
        for i in range(n):
            heapq.heappush(hea,(nums[i],i))
        for j in range(k):
            num,i = heapq.heappop(hea)
            num *= multiplier
            nums[i] = num
            heapq.heappush(hea,(num,i))
        return nums

选出和最大的K个元素

选出和最大的K个元素

在这里插入图片描述

在这里插入图片描述

  • 观察时间复杂度,发现这个如果是直接暴力的话,时间复杂度是 o ( n 2 ) o(n^2) o(n2),肯定是超标的,但是如果排序的话,就会破坏掉原本的一个对应的关系,所以考虑绑在一起,然后使用堆来维护空间为k的一个和值
import heapq
class Solution:
    def findMaxSum(self, nums1: List[int], nums2: List[int], k: int) -> List[int]:
        # 有几个关键点,一个就是得保留先前的下标,还有就是得匹配nums1 和 nums2 ,然后按照nums1进行排序
        n = len(nums1)
        # 时间消耗在这里 nlogn
        newnums = sorted(zip(nums1,nums2,list(range(n))),key = lambda x:x[0])
        ans = [0]*n
        # 这样后面可以直接替换
        hea = [0]*k
        # 现在的任务应该是首先处理一下,就是与当前的元素相同的话,就要先处理
        l = 0
        # 使用一个变量记录当前的堆的和
        s = 0
        while l < n:
            # 处理完一个元素,然后向后面查找相同的元素,然后再一起加入堆
            ans[newnums[l][2]] = s
            r = l+1
            if r >= n:
                break
            # 处理元素相同的情况
            while r < n and newnums[r][0] == newnums[l][0]:
                ans[newnums[r][2]] = ans[newnums[l][2]]
                r+=1
            # 需要往这个hea里面加入 r - l 个元素
            if r >= n:
                break
            for j in range(l,r):
                # 每一次操作就是 logk的时间复杂度
                tmp = heapq.heappop(hea)
                s -= tmp
                if tmp < newnums[j][1]:
                    heapq.heappush(hea,newnums[j][1])
                    s += newnums[j][1]
                else:
                    heapq.heappush(hea,tmp)
                    s += tmp
            l = r
        return ans
       

2406.将区间分为最少组数

2406.将区间分为最少组数

在这里插入图片描述

  • 可以看到这个分组的顺序与现在的排列是无关的,所以我们考虑首先按照区间的左端点进行升序排序
  • 考虑实际的分组的模拟操作,我们发现需要找到当前所有分组当中,右端点最小的区间,如果当前的left<这个最小的right,那么我们就需要重新开一个新的组,如果left>这个最小的right,那么我们就可以更新这个right,考虑使用维护
import heapq
class Solution:
    def minGroups(self, intervals: List[List[int]]) -> int:
        # 可以看到这个划分与实际的挑选的顺序无关,所以我们可以进行先排序处理
        intervals.sort(key = lambda x :x[0])
        # 接下来就要进行遍历,找到一种数据结构,可以找到最小值并且还能更新的
        # 那就考虑使用最小堆
        hea = []
        for left,right in intervals:
            if hea and left > hea[0]:
                heapq.heappop(hea)
                heapq.heappush(hea,right)
            else:
                heapq.heappush(hea,right)
        return len(hea)

重排元素

[模版题] 767.重构字符串

767.重构字符串

在这里插入图片描述

灵神讲解

  • 总的来说直接参透这个模版即可,模版的功能:就是可以用于构造相邻的元素不同的序列
class Solution:
    def reorganizeString(self, s: str) -> str:
        # 如果长度是奇数,那么相同的数量不能超过 n//2 + 1
        n = len(s)
        a = Counter(s).most_common()
        m = a[0][1]
        if m > n - m +1:
            return ""
        ans = ['']*n
        i = 0
        for ch,cnt in a:
            for _ in range(cnt):
                ans[i] = ch
                i += 2
                if i >=n:
                    i = 1 # 从奇数下标开始填
        return ''.join(ans)

1054.距离相等的条形码

1054.距离相等的条形码

在这里插入图片描述

  • 模版题目,减少了可行性的判断
class Solution:
    def rearrangeBarcodes(self, barcodes: List[int]) -> List[int]:
        n = len(barcodes)
        ans = [0]*n
        a = Counter(barcodes).most_common()
        i = 0
        for num ,cnt in a:
            for _ in range(cnt):
                ans[i] = num
                i+=2
                if i >= n:
                    # 从奇数开始
                    i = 1
        return ans

第K大/小元素

反悔堆

LCP.30魔塔游戏

LCP.30魔塔游戏

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

import heapq
class Solution:
    def magicTower(self, nums: List[int]) -> int:
        # 首先判断能否去?其实就统计总和是否》=0即可。
        # 在可以到达的时候,最多调整次数为负数的次数
        if not sum(nums)>=0:
            return -1
        # 可以到达
        # 其实可以统计一个数的左边最小的负数,包含当前的数
        n = len(nums)
        cur = 1
        hp = []
        ans = 0
        # 使用小根堆进行存储当前的负数的情况
        for i in range(n):
            # 负数的话就加入
            if nums[i] < 0:
                heapq.heappush(hp,nums[i])
            # 无论正负,都加入cur
            cur+=nums[i]
            # 如果栈中还有元素,并且当前没有血量,就弹出反悔最小的负数
            while hp and cur <= 0:
                p = heapq.heappop(hp)
                ans+=1
                cur+=abs(p)
        return ans

相关文章:

  • Rat工具:XiebroC2 一款国产C2工具简单使用介绍
  • 第四章:反射-Reflecting Your World《Unity Shaders and Effets Cookbook》
  • 2025.3.3-2025.3.9学习周报
  • 零基础上手Python数据分析 (1):Windows环境配置与开发工具,开启数据科学之旅!
  • Spring Cloud Gateway 笔记
  • 微软程序的打包格式MSIX
  • [项目]基于FreeRTOS的STM32四轴飞行器: 五.Motor驱动
  • Llama factory微调后的模型怎么通过ollama发布
  • Android 调用c++报错 exception of type std::bad_alloc: std::bad_alloc
  • 防火墙IPSec (无固定IP地址---一对多)
  • C++之vector类(超详解)
  • 【UCB CS 61B SP24】Lecture 28 - Tries 学习笔记
  • 使用 Elastic-Agent 或 Beats 将 Journald 中的 syslog 和 auth 日志导入 Elastic Stack
  • Go语言实战,HTTP和gRPC多服务启动与关闭的最佳实践
  • aws(学习笔记第三十二课) 深入使用cdk(API Gateway + event bridge)
  • 数据结构常见面试题
  • Java后端高频面经——计算机网络
  • Java线程池深度解析,从源码到面试热点
  • sudo systemctl restart docker 重启docker失败
  • 【数据结构】关键路径
  • 如何破解网站后台管理/百度信息流是什么
  • wordpress更多的模板/seo的优化方向
  • 软件综合课设做网站/搜索引擎优化的核心是
  • 建程网上的工程是真的吗?/百度seo排名软
  • 做网站需要会写代码/运营推广的方式和渠道
  • 常州市做网站的公司/网站宣传费用