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

[仓颉Cangjie刷题模板] 优先队列(含小顶堆实现)

@[TOC]([仓颉Cangjie刷题模板] 优先队列(含小顶堆实现) )

一、 算法&数据结构

1. 描述

堆是一个可以维护实时最大/最小值的数据结构,相比treeset等常数优很多。
常用于维护一组数据的极值贪心问题。

2. 复杂度分析

  1. 初始化O(n)
  2. 查询O(1)
  3. 修改O(lgn)

3. 常见应用

  1. Dijkstra
  2. 丑数II
  3. 3D接雨水

4. 常用优化

  1. 本文模板实现的是小顶堆,要用大顶堆可以取反。
  2. 注意经常要用的元组,在仓颉里不能比大小,因此可以用数组代替,并实现扩展排序(但是很麻烦);或者自己实现元组(pair等)

二、 模板代码

1. 丑数

在这里插入图片描述

例题: 264. 丑数 II

按照从小到大的顺序枚举每个丑数可以派生的丑数,那么第k次出堆的那个就是答案。


extend<T> Array<T> where T <: Less<T> {
    operator func <(rhs: Array<T>): Bool {
        for (i in 0..min(size, rhs.size)) {
            if (this[i] < rhs[i]) {
                return true
            }
        }
       
        return this.size < rhs.size
    }
    // public func equals(other: Array<T>){
    //     return true
    // }
}
class MinHeap<T> <: Collection<T> where T <: Less<T> {
  
    public prop size: Int {
        get() {h.size}
    }
    protected var h = ArrayList<T>()
    public init() {           }   
    public init(items: Collection<T>) {
        h.appendAll(items)
        for (i in (h.size/2)..=0:-1) {
            _siftup(i)
        }        
    }
    public func isEmpty() {
        return h.isEmpty()
    }
    public func iterator() {
        throw Exception("No Iterator for MinHeap")
        // return h.iterator()
    }
    public func heappush(v:T) {
        h.append(v)
        var i = h.size - 1
        while (i > 0 &&  v < (h[(i-1) >> 1])) {  // 比父节点小,则上移
            h[i] = h[(i-1) >> 1]
            i = (i-1) >> 1
        }
        h[i] = v
    }
    public func heappop() {
        // let last = h.remove(h.size-1)
        // if (h.size == 0) {
        //     return last
        // }
        // let ret = h[0]
        // h[0] = last 
        // _siftup(0)
        // return ret
        let ret = h[0]
        h[0] = h[h.size-1]
        h.remove(h.size-1)
        if (!h.isEmpty()) {
            _siftup(0)
        }
        return ret
    }
    public func heapreplace(v:T) {  // 替换并返回堆顶
        let ret = h[0]
        h[0] = v 
        _siftup(0)
        return ret
    }
    public func heappushpop(v:T) {  // 把v和堆顶保留更大的那个,pop返回更小的那个;常用语保留最大的k个值(小顶堆)
        if (!h.isEmpty() && h[0] < v) {
            let ret = h[0]
            h[0] = v 
            return ret
        }         
        return v
    }
    private func _siftup(i:Int64){
        // 把i位置的大值下沉,小儿子提上来
        var fa = i
        let v = h[fa]
        let n = h.size 
        while ( (fa << 1 | 1) < n) {  // 有左儿子
            var child = fa << 1 | 1 
            let right = child + 1
            if (right < n && h[right] < h[child]) {
                child = right 
            }
            if (h[child] < v) {
                h[fa] = h[child]  // 小的儿子上移
                fa = child  // 迭代
            } else {
                break
            }
        }
        if (fa != i) {  // 有变化
            h[fa] = v
        }
    } 
}
extend<T> MinHeap<T> <: ToString where T <: ToString {
    public func toString() {         
        return h.toString()      
    }
}
public class Solution {
    public func nthUglyNumber(n: Int64): Int64 {
        let h = MinHeap<Int64>([1])
        let vis = HashSet<Int64>();
        let q = [2,3,5]
        for (_ in 0..n-1) {
            let v = h.heappop()
            for (i in q) {
                let p = i*v
                if (vis.contains(p)) {
                    continue
                }
                vis.put(p)
                h.heappush(p)
            }
        }
        return h.heappop()
        
    }
}

2. Dijkstra模板体

例题: 743. 网络延迟时间

跑一遍Dij,距离最大的就是答案


import std.collection.*
import std.math.*


class MinHeap<T> <: Collection<T> where T <: MyLess<T> {
  
    public prop size: Int {
        get() {h.size}
    }
    protected var h = ArrayList<T>()
    public init() {           }   
    public init(items: Collection<T>) {
        h.appendAll(items)
        for (i in (h.size/2)..=0:-1) {
            _siftup(i)
        }        
    }
    public func isEmpty() {
        return h.isEmpty()
    }
    public func iterator() {
        throw Exception("No Iterator for MinHeap")
        // return h.iterator()
    }
    public func heappush(v:T) {
        h.append(v)
        var i = h.size - 1
        while (i > 0 &&  v < (h[(i-1) >> 1])) {  // 比父节点小,则上移
            h[i] = h[(i-1) >> 1]
            i = (i-1) >> 1
        }
        h[i] = v
    }
    public func heappop() {
        // let last = h.remove(h.size-1)
        // if (h.size == 0) {
        //     return last
        // }
        // let ret = h[0]
        // h[0] = last 
        // _siftup(0)
        // return ret
        let ret = h[0]
        h[0] = h[h.size-1]
        h.remove(h.size-1)
        if (!h.isEmpty()) {
            _siftup(0)
        }
        return ret
    }
    public func heapreplace(v:T) {  // 替换并返回堆顶
        let ret = h[0]
        h[0] = v 
        _siftup(0)
        return ret
    }
    public func heappushpop(v:T) {  // 把v和堆顶保留更大的那个,pop返回更小的那个;常用语保留最大的k个值(小顶堆)
        if (!h.isEmpty() && h[0] < v) {
            let ret = h[0]
            h[0] = v 
            return ret
        }         
        return v
    }
    private func _siftup(i:Int64){
        // 把i位置的大值下沉,小儿子提上来
        var fa = i
        let v = h[fa]
        let n = h.size 
        while ( (fa << 1 | 1) < n) {  // 有左儿子
            var child = fa << 1 | 1 
            let right = child + 1
            if (right < n && h[right] < h[child]) {
                child = right 
            }
            if (h[child] < v) {
                h[fa] = h[child]  // 小的儿子上移
                fa = child  // 迭代
            } else {
                break
            }
        }
        if (fa != i) {  // 有变化
            h[fa] = v
        }
    } 
}
interface MyLess<T> {
    operator func <(rhs: T): Bool
}
extend<T> Array<T> <: MyLess<Array<T>> where T <: Less<T> { 
    public operator func <(rhs: Array<T>): Bool {
        for (i in 0..min(size, rhs.size)) {
            if (this[i] < rhs[i]) {
                return true
            } else if (rhs[i] < this[i]) {
                return false
            }
        }
       
        return this.size < rhs.size
    }
    // public func equals(other: Array<T>){
    //     return true
    // }
}
extend<T> MinHeap<T> <: ToString where T <: ToString {
    public func toString() {         
        return h.toString()      
    }
}

public class Solution {
   public func networkDelayTime(times: Array<Array<Int64>>, n: Int64, k: Int64): Int64 {
        let g = Array(n, {_=>ArrayList<(Int64,Int64)>()})
        for (e in times) {
            let (u,v,w) = (e[0],e[1],e[2])
        
            g[u-1].append((v-1,w))
        }
        
        let dis = Array(n, {_=>Int64.Max})
        dis[k-1] = 0
        let h = MinHeap([[0,k-1]])
        while (!h.isEmpty()) {
            let arr = h.heappop()
      
            let (c, u) = (arr[0],arr[1])
            if (c > dis[u]) {
                continue
            }
            for (e in g[u]){
                let (v, w) = (e[0],e[1])
               
                if (c + w < dis[v]) {
                    dis[v] = c+w 
                    h.heappush([c+w,v])
                }
            }
        }
        let ans = max(dis).getOrThrow()
    
        return  if (ans == Int64.Max){-1} else {ans}
    }
}

三、其他

  1. 堆本质是一种贪心,因此在很多场景都有应用。比如区间离线问题

四、更多例题

五、参考链接

  • [python刷题模板] 单调队列

http://www.kler.cn/a/411076.html

相关文章:

  • 从零开始学GeoServer源码(二)添加支持arcgis切片功能
  • 预告|ROS中超好用固定翼仿真开源平台即将上线!
  • 基于FPGA的2FSK调制-串口收发-带tb仿真文件-实际上板验证成功
  • Matlab 深度学习 PINN测试与学习
  • Apache Maven 标准文件目录布局
  • 数学建模_基于对数和傅里叶变换的多通道图像增强模型(处理模糊)Matlab代码包教会使用,直接替换数据即可
  • 开展网络安全成熟度评估:业务分析师的工具和技术
  • postgres-howto 学习笔记
  • 微信小程序学习指南从入门到精通
  • 【2024】前端学习笔记19-ref和reactive使用
  • SpringCloud之Eureka:服务注册与发现全面教程!
  • TCP/IP学习笔记
  • 平安科技Java面试题及参考答案
  • 浅谈人工智能之基于容器云进行文生视频大模型搭建
  • 零基础学安全--云技术基础
  • Vue3常见Composition API详解(适用Vue2学习进入Vue3学习)
  • testImplementation和androidTestImplementation区别
  • 力扣 53. 最大子数组和
  • 《PH47 快速开发教程》发布
  • 华三(HCL)和华为(eNSP)模拟器共存安装手册
  • SpringBoot - 优雅的实现【账号登录错误次数的限制和锁定】
  • 类和对象(下):点亮编程星河的类与对象进阶之光
  • 【PTA】【数据库】【SQL命令】编程题2
  • MR30分布式 IO 模块在冷却水泵系统中的卓越应用
  • 通过异步使用消息队列优化秒杀
  • Web开发技术栈选择指南