HOT 100(七)栈、堆、贪心算法

news2024/11/23 11:56:17

一、栈

1、每日温度

使用单调递减栈来解决。主要思路是遍历temperatures数组,利用栈来存储还没有找到比当前温度高的天数的索引。当遇到比栈顶索引所对应温度更高的温度时,就可以确定当前这一天的温度比之前那一天高。索引的差值就是等待的天数

求一个元素右边或者左边第一个比它大/小的元素可以用到单调栈。

class Solution:
    def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
        n=len(temperatures)
        stk=[]
        ans=[0]*n
        for i in range(n):
            tmp=temperatures[i]
            while stk and tmp>temperatures[stk[-1]]:
                pre_pos=stk.pop()
                ans[pre_pos]=i-pre_pos
            stk.append(i)
        return ans

2、柱状图中最大的矩形 

代码随想录题解icon-default.png?t=O83Ahttp://【单调栈,又一次经典来袭! LeetCode:84.柱状图中最大的矩形】https://www.bilibili.com/video/BV1Ns4y1o7uB?vd_source=b93b9c2a7846dd3e8bd33feb227c4ac5通过使用单调递增栈来解决这个问题。当遇到一个比栈顶元素低的高度时,说明以栈顶高度为矩形的柱子已经结束,它无法再延伸更大的宽度,因此可以计算这个柱子形成的最大矩形面积。

单调栈的核心是维护一个递增序列。具体思路是:

  • 如果当前柱子的高度大于栈顶柱子的高度,则将当前柱子的索引压入栈。
  • 如果当前柱子的高度小于栈顶柱子的高度,说明栈顶柱子的矩形已经找到了右边界,因此我们可以计算以该柱子为高度的最大矩形面积。
class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        heights=[0]+heights+[0]
        res=0
        stk=[0]
        for i in range(1,len(heights)):
            if heights[i]>heights[stk[-1]]:
                stk.append(i)
            elif heights[i]==heights[stk[-1]]:
                stk.pop()
                stk.append(i)
            else:
                while stk and heights[stk[-1]]>heights[i]:
                    mid_height_pos=stk.pop()
                    mid_height=heights[mid_height_pos]
                    left_edge=stk[-1]
                    right_edge=i
                    res=max(res,(right_edge-left_edge-1)*mid_height)
                stk.append(i)
        return res

二、堆

1、数组中的第k个最大元素

①快速排序思想

题目要求是找出数组中第k个最大元素,因此可以通过快速排序不断缩小寻找区间来定位第k个最大的元素。(题目要求找的是数组中第k个最大的元素,因此排序后的元素是从大到小逆序排列的,左右指针移动的判断条件不要写错)。

与快速排序不同的是,不需要完全排序整个数组,只需要处理包含第 k 大元素的那一部分。因此每交换过一轮元素以后,都要判定第k大的元素在左边部分(每次的起始left到j)还是右部分(j+1到right)。

class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:
        def quicksort(nums,left,right,k):
            if left>=right:
                return nums[left]
            mid=(left+right)//2
            pivot=nums[mid]
            i,j=left-1,right+1
            while i<j:
                while True:
                    i+=1
                    if nums[i]<=pivot:
                        break
                while True:
                    j-=1
                    if nums[j]>=pivot:
                        break
                if i<j:
                    nums[i],nums[j]=nums[j],nums[i]
            if j-left+1>=k:
                return quicksort(nums,left,j,k)
            else:
                return quicksort(nums,j+1,right,k-(j-left+1))
        return quicksort(nums,0,len(nums)-1,k)

②堆

维护一个大小为 k 的小根堆。每次当堆的大小超过 k 时,弹出堆顶元素,因为堆顶元素是堆中最小的,这样可以确保堆中始终保留了 k 个最大的元素。最后堆顶的元素就是第 k 大的元素。

class Solution:
    def findKthLargest(self, nums: List[int], k: int) -> int:
        min_heap=[]
        for num in nums:
            heapq.heappush(min_heap,num)
            if len(min_heap)>k:
                heapq.heappop(min_heap)
        return min_heap[0]

2、前K个高频元素

1-数组中的第k个最大元素中堆处理方法处理思想相同。

首先调用Counter方法获取每个元素与其出现次数,再构建一个小根堆来存放(出现次数,数组元素)堆顶是出现次数最少的数组元素。每当堆的大小超过k,就将堆顶元素弹出,这样最后留在堆中的一定是出现次数最多的那K个数组元素。

class Solution:
    def topKFrequent(self, nums: List[int], k: int) -> List[int]:
        n=len(nums)
        min_heap=[]
        counter=Counter(nums)
        for num,count in counter.items():
            heapq.heappush(min_heap,(count,num))
            if len(min_heap)>k:
                heapq.heappop(min_heap)
        top_k=[heapq.heappop(min_heap)[1] for _ in range(len(min_heap))]
        return top_k

3、数据流的中位数

整体思路:

  • 使用一个最大堆(通过存负值模拟)来保存数据流中较小的一半元素。
  • 使用一个最小堆来保存数据流中较大的一半元素。
  • 保持最大堆的大小总是等于最小堆的大小或者比最小堆大一个元素,这样中位数可以轻松获取:
    • 如果两个堆的大小相同,则中位数是两个堆顶元素的平均值。
    • 如果最大堆比最小堆大一个元素,则中位数是最大堆的顶部元素。

详细步骤:

  • 添加元素:

    • 首先添加到最大堆: 元素以其负值形式添加到最大堆中。
    • 调整元素到最小堆: 如果添加后最大堆的堆顶元素(负值的最小值,即绝对值最大)大于最小堆的堆顶元素,则将最大堆的顶部元素弹出(转换为正值),并加入到最小堆中。这样做是为了保证最小堆中的所有元素始终大于最大堆中的所有元素。
    • 平衡两个堆的大小:
      • 如果最大堆的大小比最小堆大超过1个元素,从最大堆中移除顶部元素(最大值),转换为正值后加入到最小堆中。
      • 如果最小堆比最大堆大(虽然按照逻辑不应该发生,但为了保证健壮性也可以检查和处理),则将最小堆的顶部元素弹出并加入到最大堆中。
  • 计算中位数:

    • 如果最大堆的元素数量比最小堆多,中位数是最大堆的堆顶元素(转换为正值)。
    • 如果最大堆和最小堆的大小相同,中位数是两个堆顶元素值的平均数。
class MedianFinder:
    def __init__(self):
        self.min_heap=[]
        self.max_heap=[]
    def addNum(self, num: int) -> None:
        heapq.heappush(self.max_heap,-num)
        if self.max_heap and self.min_heap and -self.max_heap[0]>self.min_heap[0]:
            heapq.heappush(self.min_heap,-heapq.heappop(self.max_heap))
        if len(self.max_heap)>len(self.min_heap)+1:
            heapq.heappush(self.min_heap,-heapq.heappop(self.max_heap))
        if len(self.min_heap)>len(self.max_heap):
            heapq.heappush(self.max_heap,-heapq.heappop(self.min_heap))

    def findMedian(self) -> float:
        if len(self.max_heap)==len(self.min_heap):
            return (-self.max_heap[0]+self.min_heap[0])/2.0
        else:
            return -self.max_heap[0]



# Your MedianFinder object will be instantiated and called as such:
# obj = MedianFinder()
# obj.addNum(num)
# param_2 = obj.findMedian()

 三、贪心算法

1、买卖股票的最佳时机

利用了动态规划的思想,通过在每个价格点更新历史最低价格和当前可能的最大利润。

  • prices 数组中的每一个 price 进行迭代。
  • maxprofit 更新为 max(price-minprice,maxprofit)。每次计算当前价格 price 和之前最低价格 minprice 的差价,并与当前记录的 maxprofit 比较,取较大值。这样可以保证每天考虑卖出股票时,都是基于之前买入价格最低的情况来计算可能的最大利润。
  • minprice 更新为 min(price,minprice)。这一步确保在遍历到当前价格 price 时,minprice 总是记录到目前为止的最低股票价格。
class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        max_profit=0
        min_price=float('inf')
        for price in prices:
            max_profit=max(price-min_price,max_profit)
            min_price=min(min_price,price)
        return max_profit

2、跳跃游戏

用right来记录当前能够跳到的最右位置,遍历数组更新right,如果最后right>=n-1就说明能够到达终点。

更新的规则:如果当前位置i在right能到达的范围之内(也就是i<=right),则更新right,right=max(right,nums[i]+i)。

class Solution:
    def canJump(self, nums: List[int]) -> bool:
        n=len(nums)
        right=0
        for i in range(n):
            if i<=right:
                right=max(right,nums[i]+i)
                if right>=n-1:
                    return True
        return False

3、跳跃游戏II

在每个跳跃点,总是尝试到达当前可知范围内的最远点,这是局部最优的选择。通过局部最优的方式逐步推进,累计的跳跃次数应是全局最优的,即最少的跳跃次数到达终点。

遍历数组的每个元素(除了最后一个,因为跳跃行为是从当前位置到后面的某个位置),在每个位置做以下操作:

  • 更新right:right=max(right,i+nums[i]),表示在目前这个跳跃周期内,能够到达的最远极限。
  • 检查是否到达了当前跳跃的边界end
    • 如果到达,说明需要执行一次跳跃到新的位置,即更新 jumps,并将 end 设置为当前已知的right
    • 每次更新 end 后,检查 end 是否已经达到或超过了数组的最后一个位置。如果是,可以直接结束循环。
class Solution:
    def jump(self, nums: List[int]) -> int:
        if len(nums)<=1:
            return 0
        n=len(nums)
        jump=0
        right=0
        end=0
        for i in range(n):
            right=max(right,i+nums[i])
            if i==end:
                jump+=1
                end=right
                if end>=n-1:
                    break
        return jump

4、划分字母区间

题意要求每一个字母最多出现在一个片段内,也就是说每个字符不应跨越到其他分割中。

首先,初始化一个长度为26的数组last,用于跟踪字符串中每个字符的最后出现位置。

然后再用start和end分别标记当前片段的起始位和终止点,partition用于存放分割片段大小。

遍历字符串,不断比较、更新end为当前片段中字符最后出现位置的最大值,这能保证当前片段中所有字符不跨越到其他分割中。

class Solution:
    def partitionLabels(self, s: str) -> List[int]:
        last=[0]*26
        for i,ch in enumerate(s):
            pos=ord(ch)-ord('a')
            last[pos]=i
        start=0
        end=0
        partition=[]
        for i,ch in enumerate(s):
            pos=ord(ch)-ord('a')
            end=max(end,last[pos])
            if i==end:
                partition.append(end-start+1)
                start=end+1
        return partition

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2114376.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端 Vue3 项目开发—— ESLint prettier 配置代码风格

ESLint & prettier 介绍 如果你用的是 pnpm create vue 来创建项目&#xff0c;那么创建项目时就会让你选择是否添加 ESLint 和 prettier 我们在上一篇博客中详细介绍过 ESLint&#xff0c;可以说上一篇博客是这篇博客的先修知识&#xff0c;所以各位小伙伴们请先去看看我…

微信小程序页面制作——个人信息

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

Docker | 虚拟机 是一个东西吗

文章目录 虚拟机与Docker如果要在linux环境下运行程序&#xff0c;那么docker会给我下载整个linux操作系统吗&#xff1f;Docker的一些名词 虚拟机与Docker 虚拟机就相当于买了一台新电脑&#xff0c;有了完整的独立的一个操作系统Docker 不需要创建完整的虚拟操作系统&#xf…

el-table行编辑

需求&#xff1a;单点行编辑并且请求接口更新数据&#xff0c;表格中某几个字段是下拉框取值的&#xff0c;剩下的是文本域&#xff1b;展示的时候 需要区分下拉框编码还是中文 故障模式这个展示的是fault_mode编码,但要显示的文字fault_mode_chn 这点需要注意 <el-tablere…

【H2O2|全栈】关于Photoshop | PS(4)

PS的一些杂谈&#xff08;亖&#xff09; 目录 PS的一些杂谈&#xff08;亖&#xff09; 前言 准备工作 图形工具 基本属性 混合选项 形状图层 文字工具 基本属性 进一步变化文字 组和图层 UI设计案例 预告和回顾 后话 前言 这一篇博客我将会写一下图形工具和…

数据链路层以太网技术与DNS、ICMP协议

我们前面学习到的传输层、网络层。传输层是保证数据可靠传输。而网络层是实现在复杂的网络环境中确定一个合适的路径。我们接下来所说的数据链路层其实就是用于两个设备(同一种数据链路节点)之间进行传递。其实也就是如数次的局域网中设备之间的转发过程。 认识以太网 "…

大数据-124 - Flink State 01篇 状态原理和原理剖析:状态类型 执行分析

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

Pr:首选项 - 音频硬件

Pr菜单&#xff1a;编辑/首选项 Edit/Preferences Premiere Pro 首选项中的“音频硬件” Audio Hardware选项卡可以指定计算机的音频设备和设置&#xff0c;还可以指定 Pr 用于音频回放和录制的 ASIO 和 MME 设置&#xff08;仅限 Windows&#xff09;或 CoreAudio 设置&#x…

C#使用GDI+实现生成验证码

目录 下面是代码的详细解释&#xff1a; 类声明和成员变量 构造函数 窗体加载事件 生成验证码方法 pictureBox1 点击事件 按钮点击事件 完整代码&#xff1a; 总结 这段代码是一个C# Windows Forms应用程序的一部分&#xff0c;用于生成和验证验证码。 下面是代码的详细解…

C# Windows Forms实现绘制画板

目录 C# Windows Forms上绘制画板&#xff1a; 详细解释&#xff1a; TempData临时数据&#xff0c;用来保存画笔相关的信息&#xff0c;如&#xff1a;颜色&#xff0c;大小&#xff0c;坐标等 类声明和成员变量 构造函数 文件菜单项点击事件 保存菜单项点击事件 画笔大…

浙大数据结构:03-树2 List Leaves

这道题我借用了一点上一题的代码思路&#xff0c;这题考察的主要是层序遍历&#xff0c;即用队列来实现&#xff0c;当然此处我依然采用数组模拟队列来实现。 机翻 1、条件准备 map的键存下标&#xff0c;后面值分别存左右子树的下标&#xff0c;没有子树就存-1. head数组只…

python脚本源码如何使用PyOxidizer编译Windows可执行文件

使用 PyOxidizer 将上述代码编译为 Windows 可执行文件&#xff0c;可以按照以下步骤进行&#xff1a; 一、准备工作 确保已经安装了 PyOxidizer 和 Rust 开发环境&#xff0c;如前文所述。 二、创建 PyOxidizer 配置文件 创建一个名为pyoxidizer.toml的配置文件&#xff0c;内…

go急速入门API开发

go急速入门 1、安装Go和对应编辑器2、编写helloWord3、项目目录开发4、编写一个http服务器5、 使用Gin框架基本使用使用部分中间件自定义中间件 6、部署 1、安装Go和对应编辑器 go官网&#xff0c;下载自己电脑对应版本即可。安装完成之后打开cmd输入go即可弹出对应提示。 对…

ffmpeg(各个系统版本安装- Windows11-Mac-Linux)

各个系统上的安装不建议使用编译安装&#xff0c;大佬的话可以 编译安装会各种环境问题&#xff0c;直接使用别人安装好的就行 1.Windows11上安装ffmpeg 1.官网下载ffmpeg 进入Download FFmpeg网址&#xff0c;点击下载windows版ffmpeg&#xff0c;使用别人编译好的版本即可 …

文法的例题

答案&#xff1a;B 知识点&#xff1a; 文法 一个形式文法是一个有序四元组G{V,T,S,P}&#xff0c;其中&#xff1a; V&#xff1a;非终结符。不是语言组成部分&#xff0c;不是最终结果&#xff0c;可理解为占位符 T&#xff1a;终结符。是语言的组成部分&#xff0c;是最…

自用NAS系列1-设备

拾光坞 拾光坞多账号绑定青龙面板SMBWebdav小雅alist下载到NASDocker安装迅雷功能利用qBittorrentEEJackett打造一站式下载工具安装jackett插件 外网访问内网拾光客户端拾光穿透公网ipv6路由器配置ipv6拾光坞公网验证拾光坞域名验证 拾光坞 多账号绑定 手机注册拾光坞账号&am…

Web Bluetooth 与点对点连接

前言 需求需要实现手持终端设备与 web 网页的点对点数据传输&#xff0c;不希望有服务器参与&#xff0c;想到了 web 的 USB 与 Bluetooth API&#xff0c;对 Web Bluetooth API 进行了研究。 蓝牙 GATT 基础知识 GATT&#xff08;通用属性配置文件&#xff0c;蓝牙低功耗&a…

K8S 发布应用

前言 昨儿个用 unbuntu20.04 又装了一次K8S 用的 kubeadm containerd Cilium (CNI) 又重新撸了一遍 这里只记录 应用发布的笔记 正文 #创建deployment kubectl create deployment nginx --imagenginx #我这边大约30秒后显示为 ready kubectl get deployments kubectl desc…

4.7 Sensors -- useScroll

4.7 Sensors – useScroll https://vueuse.org/core/useScroll/ 作用 响应式的监听滚动位置和状态。 官方示例 <script setup lang"ts"> import { useScroll } from vueuse/coreconst el ref<HTMLElement | null>(null) const { x, y, isScrolling…

【Python系列】只更新非空的字段

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…