【算法】单调栈题单(矩阵系列、字典序最小、贡献法)⭐

news2025/1/15 17:22:25

文章目录

  • 题单来源
  • 经典题单
    • 496. 下一个更大元素 I(单调栈模板题)
    • 503. 下一个更大元素 II(单调栈+循环数组)
    • 2454. 下一个更大元素 IV(第二个更大的元素:两个单调栈)
    • 456. 132 模式(单调栈找上一个更大元素+哈希表记录最小值)
    • 739. 每日温度
    • 901. 股票价格跨度
    • 1019. 链表中的下一个更大节点
    • 1124. 表现良好的最长时间段(单调栈解法⭐⭐⭐⭐⭐)
    • 1475. 商品折扣后的最终价格(单调栈找下一个更小的元素)
    • 2289. 使数组按非递减顺序排列⭐⭐⭐⭐⭐
      • 解法——等价转换 + 利用单调性🐂
  • 矩形系列
  • 字典序最小
  • 贡献法
    • 2818. 操作使得分最大(⭐质因数分解+单调栈贡献法+排序贪心)好题!
    • 更多题目

题单来源

https://leetcode.cn/problems/beautiful-towers-ii/solutions/2456562/qian-hou-zhui-fen-jie-dan-diao-zhan-pyth-1exe/

经典题单

496. 下一个更大元素 I(单调栈模板题)

https://leetcode.cn/problems/next-greater-element-i/description/
在这里插入图片描述
提示:

1 <= nums1.length <= nums2.length <= 1000
0 <= nums1[i], nums2[i] <= 10^4
nums1和nums2中所有整数 互不相同
nums1 中的所有整数同样出现在 nums2 中

进阶:你可以设计一个时间复杂度为 O(nums1.length + nums2.length) 的解决方案吗?

预先处理出 nums2 数组中每个数字的下一个更大数字,存储在哈希表中。
生成 ans 数组时,从哈希表中逐个取结果即可。

class Solution {
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
        int n = nums1.length;
        Map<Integer, Integer> m = new HashMap<>();
        Deque<Integer> stk = new ArrayDeque<>();
        for (int i = 0; i < nums2.length; ++i) {
            while (!stk.isEmpty() && nums2[i] > stk.peek()) m.put(stk.pop(), nums2[i]);
            stk.push(nums2[i]);
        }
        int[] ans = new int[n];
        for (int i = 0; i < n; ++i) {
            ans[i] = m.getOrDefault(nums1[i], -1);
        }
        return ans;
    }
}

503. 下一个更大元素 II(单调栈+循环数组)

https://leetcode.cn/problems/next-greater-element-ii/description/

在这里插入图片描述

class Solution {
    public int[] nextGreaterElements(int[] nums) {
        int n = nums.length;
        int[] ans = new int[n];
        Arrays.fill(ans, -1);
        Deque<Integer> stk = new ArrayDeque<>();
        for (int i = 0; i < 2 * n - 1; ++i) {
            int id = i % n;
            while (!stk.isEmpty() && nums[id] > nums[stk.peek()]) ans[stk.pop()] = nums[id];
            stk.push(id);
        }
        return ans;
    }
}

2454. 下一个更大元素 IV(第二个更大的元素:两个单调栈)

https://leetcode.cn/problems/next-greater-element-iv/description/
在这里插入图片描述

提示:
1 <= nums.length <= 10^5
0 <= nums[i] <= 10^9

用两个单调栈来分别处理第一个和第二个更大,当第一次被弹出时,说明遇到了第一个更大的元素,将其弹出后放入第二个单调栈中。

在第二个单调栈被弹出的元素说明遇到了第二个更大的元素。

class Solution {
    public int[] secondGreaterElement(int[] nums) {
        int n= nums.length;
        int[] ans = new int[n];
        Arrays.fill(ans, -1);
        Deque<Integer> stk = new ArrayDeque<>(), stk2 = new ArrayDeque<>();
        for (int i = 0; i < n; ++i) {
            // 处理第二个单调栈
            while (!stk2.isEmpty() && nums[i] > nums[stk2.peek()]) {
                ans[stk2.pop()] = nums[i];
            }
            // 处理第一个单调栈
            List<Integer> ls = new ArrayList<>();
            while (!stk.isEmpty() && nums[i] > nums[stk.peek()]) {
                ls.add(stk.pop());
            }
            for (int j = ls.size() - 1; j >= 0; --j) stk2.push(ls.get(j));
            stk.push(i);
        }
        return ans;
    }
}

456. 132 模式(单调栈找上一个更大元素+哈希表记录最小值)

https://leetcode.cn/problems/132-pattern/description/

在这里插入图片描述

枚举的x作为最后一个数字,当找到上一个更大的数字时,考虑其之前出现的最小值是否小于当前值即可。

class Solution {
    public boolean find132pattern(int[] nums) {
        // 找上一个更大元素,并检查当前是否大于更大元素之前出现过的最小值
        int mn = Integer.MAX_VALUE;     // 记录已经枚举过的数值中的最小值
        Deque<Integer> stk = new ArrayDeque<>();
        Map<Integer, Integer> m = new HashMap<>();  // 记录各个数值之前出现的最小值
        for (int x: nums) {
            m.put(x, mn);
            while (!stk.isEmpty() && x >= stk.peek()) {
                stk.pop();
            }
            if (!stk.isEmpty() && x > m.get(stk.peek())) return true;
            stk.push(x);
            if (x < mn) mn = x;
        }
        return false;
    }
}

739. 每日温度

https://leetcode.cn/problems/daily-temperatures/description/

在这里插入图片描述

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        int n = temperatures.length;
        int[] ans = new int[n];
        Deque<Integer> stk = new ArrayDeque<>();
        for (int i = 0; i < n; ++i) {
            // 维护单调递减的单调栈
            while (!stk.isEmpty() && temperatures[i] > temperatures[stk.peek()]) {
                // 当元素被弹出时,说明遇到了更大的值
                ans[stk.peek()] = i - stk.pop();
            }
            stk.push(i);
        }
        return ans;
    }
}

901. 股票价格跨度

https://leetcode.cn/problems/online-stock-span/description/
在这里插入图片描述
提示:
1 <= price <= 10^5
最多调用 next 方法 10^4 次

class StockSpanner {
    int t = 0;
    // 单调递减的单调栈
    Deque<Integer> stk = new ArrayDeque<>();
    List<Integer> ls = new ArrayList<>();

    public StockSpanner() {
        stk.push(-1);
    }
    
    public int next(int price) {    
        ls.add(price);
        while (stk.size() > 1 && price >= ls.get(stk.peek())) {
            stk.pop();
        }
        int res = t - stk.peek();
        stk.push(t++);
        return res;
    }
}

/**
 * Your StockSpanner object will be instantiated and called as such:
 * StockSpanner obj = new StockSpanner();
 * int param_1 = obj.next(price);
 */

1019. 链表中的下一个更大节点

https://leetcode.cn/problems/next-greater-node-in-linked-list/description/
在这里插入图片描述

提示:

链表中节点数为 n
1 <= n <= 10^4
1 <= Node.val <= 10^9

存储列表后,再使用单调栈处理。

class Solution {
    public int[] nextLargerNodes(ListNode head) {
        List<Integer> ls = new ArrayList<>();
        while (head != null) {
            ls.add(head.val);
            head = head.next;
        }
        int n = ls.size();
        int[] ans = new int[n];
        Deque<Integer> stk = new ArrayDeque<>();
        for (int i = 0; i < n; ++i) {
            while (!stk.isEmpty() && ls.get(i) > ls.get(stk.peek())) {
                ans[stk.pop()] = ls.get(i);
            }
            stk.push(i);
        }
        return ans;
    }
}

1124. 表现良好的最长时间段(单调栈解法⭐⭐⭐⭐⭐)

https://leetcode.cn/problems/longest-well-performing-interval/description/
在这里插入图片描述
提示:
1 <= hours.length <= 10^4
0 <= hours[i] <= 16

先正序遍历用单调栈处理,再反向遍历利用单调栈中结果。

class Solution {
    public int longestWPI(int[] hours) {
        int n = hours.length;
        int[] s = new int[n + 1];
        ArrayDeque<Integer> stk = new ArrayDeque<>();
        stk.push(0);
        // 单调递减的单调栈
        for (int i = 1; i <= n; ++i) {
            s[i] = s[i - 1] + (hours[i - 1] > 8? 1: -1);
            if (s[i] < s[stk.peek()]) stk.push(i);
        }
        int ans = 0;
        for (int i = n; i > 0; --i) {
            while (!stk.isEmpty() && s[i] > s[stk.peek()]) {
                ans = Math.max(ans, i - stk.pop());
            }
        }
        return ans;
    }
}

1475. 商品折扣后的最终价格(单调栈找下一个更小的元素)

https://leetcode.cn/problems/final-prices-with-a-special-discount-in-a-shop/description/
在这里插入图片描述

提示:
1 <= prices.length <= 500
1 <= prices[i] <= 10^3

class Solution {
    public int[] finalPrices(int[] prices) {
        int n = prices.length;
        // 单调栈找下一个<=的元素
        Deque<Integer> stk = new ArrayDeque<>();
        for (int i = 0; i < n; ++i) {
            while (!stk.isEmpty() && prices[i] <= prices[stk.peek()]) {
                prices[stk.pop()] -= prices[i];
            }
            stk.push(i);
        }
        return prices;
    }
}

2289. 使数组按非递减顺序排列⭐⭐⭐⭐⭐

https://leetcode.cn/problems/steps-to-make-array-non-decreasing/description/

在这里插入图片描述

提示:
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^9

解法——等价转换 + 利用单调性🐂

https://leetcode.cn/problems/steps-to-make-array-non-decreasing/solutions/1524614/by-endlesscheng-s2yc/
在这里插入图片描述

class Solution {
    public int totalSteps(int[] nums) {
        int n = nums.length;
        // 单调递减 存储元素及其被删除的时刻
        Deque<int[]> stk = new ArrayDeque<>();
        int ans = 0;
        for (int i = 0; i < n; ++i) {
            int maxT = 0;
            while (!stk.isEmpty() && nums[i] >= nums[stk.peek()[0]]) {
                maxT = Math.max(stk.pop()[1], maxT);
            }
            if (!stk.isEmpty()) ans = Math.max(ans, maxT + 1);
            stk.push(new int[]{i, maxT + 1});
        }
        return ans;
    }
}

矩形系列

见:【算法】单调栈题单——矩阵系列

字典序最小

见:【算法】单调栈题单——字典序最小

贡献法

2818. 操作使得分最大(⭐质因数分解+单调栈贡献法+排序贪心)好题!

https://leetcode.cn/problems/apply-operations-to-maximize-score/

在这里插入图片描述
提示:
1 <= nums.length == n <= 10^5
1 <= nums[i] <= 10^5
1 <= k <= min(n * (n + 1) / 2, 10^9)

出自周赛:【力扣周赛】第 358 场周赛(大杂烩题目:质因数分解+快速幂+单调栈+贡献法)

class Solution {
    final long MOD = (long)1e9 + 7;
    final static int MX = (int)1e5 + 1;

    static int[] omega = new int[MX];
    static {
        for (int i = 2; i < MX; ++i) {
            if (omega[i] == 0) {    // i 是质数
                for (int j = i; j < MX; j += i) {
                    omega[j]++;     // i 是 j 的一个质因子
                }
            }
        }
    }
    
    public int maximumScore(List<Integer> nums, int k) {
        int n = nums.size();
        int[][] scores = new int[n][2];
        for (int i = 0; i < n; ++i) {
            scores[i][0] = op(nums.get(i));         // 求质数分数
        }
        Deque<Integer> stk = new ArrayDeque<>();
        int[] l = new int[n], r = new int[n];       // 存储各个元素对应可以选择的l~r范围
        Arrays.fill(l, -1);
        Arrays.fill(r, n);
        
        for (int i = 0; i < n; ++i) {
            while (!stk.isEmpty() && scores[i][0] > scores[stk.peek()][0]) {
                r[stk.pop()] = i;
            }
            if (!stk.isEmpty()) l[i] = stk.peek();
            stk.push(i);
        }
        for (int i = 0; i < n; ++i) {
            scores[i][0] = nums.get(i);             // 元素的贡献
            scores[i][1] = (r[i] - i) * (i - l[i]); // 元素可以被选择的次数
        }
        
        // 排序+贪心找 k次操作对应哪些元素
        Arrays.sort(scores, (x, y) -> y[0] - x[0]);     // 分数倒序排序
        long ans = 1;
        for (int i = 0; i < n && k > 0; ++i) {
            if (scores[i][1] <= k) {
                ans = (ans * qmi((long)scores[i][0], (long)scores[i][1])) % MOD;
            } else {
                ans = (ans * qmi((long)scores[i][0], (long)k)) % MOD;
                break;
            }
            k -= scores[i][1];
        }
        return (int)ans;
    }
    
    // 质因数分解 得到不同质因数的数量
    public int op(int x) {
        return omega[x];
    }
    
    // 快速幂
    public long qmi(long a, long b) {
        long p = MOD;
        long res = 1 % p, t = a;
        while (b != 0) {
            if ((b & 1) == 1) res = res * t % p;
            t = t * t % p;
            b >>= 1;
        }
        return res;
    }
}

更多题目

更多见:【算法】贡献法相关题目练习

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

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

相关文章

Dockerfile与Docker网络

一、Dockerfile 1、概念&#xff1a; Dockerfile是用来构建docker镜像的文本文件&#xff0c;是由构建镜像所需要的指令和参数构建的脚本。 2、构建步骤&#xff1a; ① 编写Dockerfile文件 ② docker build命令构建镜像 ③ docker run依据镜像运行容器实例 Dockerfile …

电影《星愿》观后感

上周看了电影《星愿》&#xff0c;看这部电影的动机&#xff0c;主要是回忆的价值大于电影本身的价值&#xff0c;看着影片介绍&#xff0c;是迪士尼工作室成立百年&#xff0c;特别推出的影片。 具体来说&#xff0c;主要是在开头有一段是影片&#xff0c;各个时期的我们看过的…

Echarts大屏可视化_03 定制柱状图

柱状图模块引入 1.找到合适的图表 在echarts中寻找与目标样式相近的图表 Examples - Apache ECharts 2. 引入柱状图 使用立即执行函数构建&#xff0c;防止变量全局污染 实例化对象 将官网中提供的option复制到代码中&#xff0c;并且构建图表 // 柱状图模块1 (function () {/…

若依微服务项目整合rocketMq

原文链接&#xff1a;ttps://mp.weixin.qq.com/s/IYdo_suKvvReqCiEKjCeHw 第一步下载若依项目 第二步安装rocketMq&#xff08;推荐在linux使用docker部署比较快&#xff09; 第二步新建一个生产者模块儿&#xff0c;再建一个消费者模块 第四步在getway模块中配置接口映射规…

浅学指针(5)sizeof和strlen的进阶理解

系列文章目录 文章目录 系列文章目录前言1. sizeof和strlen的对⽐1.1 sizeofsizeof不是函数&#xff0c;是运算符 1.2 strlen1.3 sizeof 和 strlen的对⽐ 2. 数组和指针笔试题解析• sizeof(数组名)&#xff0c;sizeof中单独放数组名&#xff0c;这⾥的数组名表⽰整个数组&…

一款自动帮你生成UI界面和代码的AI神器

我的新书《Android App开发入门与实战》已于2020年8月由人民邮电出版社出版&#xff0c;欢迎购买。点击进入详情 只要描述你想要的UI是什么样的&#xff0c;它就能帮你生成&#xff0c;是不是很神奇&#xff1f; v0使用 AI 模型根据简单的文本提示生成用户界面和代码&#xff…

有序表常见题型

给定一个数组arr和两个整数a和b求arr中有多少个子数组累加和在a到b这个范围上返回达标的子数组数量 如【3&#xff0c;6&#xff0c;1&#xff0c;9&#xff0c;2】达标的子数组通过暴力求解的方式时间复杂度为O&#xff08;N的三次方&#xff09;【找每个子数组占用O&#xf…

MQ - KAFKA 基础篇

##1、KAFKA的核心组件/API Producer API&#xff0c;它允许应用程序向一个或多个 topics 上发送消息记录 Consumer API&#xff0c;允许应用程序订阅一个或多个 topics 并处理为其生成的记录流 Streams API&#xff0c;它允许应用程序作为流处理器&#xff0c;从一个或多个主…

Ubuntu中安装IDEA,并配置桌面快捷方式

1、首先自己下载linux版本的idea 这一步省略不说了 2、在/usr/local/路径下新建安装目录IDEA&#xff1a; mkdir -p /usr/local/IDEA3、执行如下命令&#xff0c;解压下载的压缩包到指定目录&#xff1a; tar -zxvf ideaIU-2022.3.3.tar.gz -C /usr/local/IDEA 注意&#x…

QT 中 QDateTime::currentDateTime() 输出格式备查

基础 QDateTime::currentDateTime() //当前的日期和时间。 QDateTime::toString() //以特定的格式输出时间&#xff0c;格式 yyyy: 年份&#xff08;4位数&#xff09; MM: 月份&#xff08;两位数&#xff0c;07表示七月&#xff09; dd: 日期&#xff08;两位数&#xff0c…

Siemens-NXUG二次开发-新建与保存prt文件[Python UF][20231204]

Siemens-NXUG二次开发-新建与保存prt文件[Python UF][20231204] 1.python uf函数1.1 NXOpen.UF.Part.New1.2 NXOpen.UF.Part.Save1.3 NXOpen.UF.Ui.OpenListingWindow1.4 NXOpen.UF.Ui.IsListingWindowOpen1.5 NXOpen.UF.Ui.WriteListingWindow1.6 NXOpen.UF.Ui.SaveListingWin…

深入了解汉字转拼音转换工具:原理与应用

一、引言 汉字作为世界上最古老、最具象形意的文字之一&#xff0c;承载了数千年的历史文明。然而&#xff0c;在现代信息技术环境下&#xff0c;汉字的输入、输出和检索等方面存在一定的局限性。拼音作为汉字的一种音标表达方式&#xff0c;能够有效地解决这些问题。本文将为…

MYSQL练题笔记-排序和分组-全7题已完成

排序和分组这部分共7道题&#xff0c;如下&#xff0c;只说一说3道&#xff0c;其他都写对了&#xff0c;也不难&#xff0c;只有最后一题难一点点&#xff0c;没想到那种解法&#xff0c;一看到主键和外键就想利用连接。 1.销售分析的题目和表相关内容如下 就是利用product_id…

会话 cookie 及隐私的那些事

什么是会话 Cookie? 会话 Cookie 的概念非常简单。 会话 Cookie,也称为临时 Cookie 或内存 Cookie,是网站在浏览会话期间存储在用户计算机或设备上的小数据片段。 它是由网站生成并由您的浏览器存储和使用的多种 Cookie 之一。 常规 Cookie 或“持久”Cookie 是通常在您的…

周周清(1)

项目进度&#xff1a; 最近一直在搭建环境&#xff0c;都没写什么&#xff1a;登陆页面采用登陆注册在同一个界面&#xff0c;用v-if进行渲染&#xff0c;并且借助validation插件中的yup神器进行校验&#xff0c; <script setup> // import { ref } from vue import * …

机器学习 - 导论

简单了解 机器学习关于数据集的概念 、

免费AI洗稿软件【2023最新】

很多时候我们需要通过文字来表达观点、推广产品或服务。然而&#xff0c;长时间的文稿创作不仅费时费力&#xff0c;还容易陷入表达瓶颈。许多写手和从业者纷纷寻找一款方便、高效的AI洗稿工具。 文心一言洗稿软件。这款软件以其独特的文风生成和洗稿功能而备受瞩目。用户只需…

思维模型 搭便车效应

本系列文章 主要是 分享 思维模型&#xff0c;涉及各个领域&#xff0c;重在提升认知。合理坐享其成。 1 搭便车效应的应用 1.1 搭便车效应在商业竞争中的应用 1 被搭便车的AT&T 在 20 世纪 80 年代&#xff0c;美国电信市场由美国电话电报公司&#xff08;AT&T&…

DNA模糊匹配(动态规划)

我做动态规划还是少的 只会做那些显而易见的动态规划题&#xff08;这题是看了给出来的解题思路做的&#xff09; 以后可能就会做与这类似的了 代码如下&#xff1a; #include<stdio.h> #include<string.h> int get_min(int a, int b, int c); int min_l[301][…

利用STM32内置温度传感器实现温度监测系统

STM32微控制器是一款强大的嵌入式处理器&#xff0c;具有广泛的应用领域。其中&#xff0c;一些STM32微控制器内置了温度传感器&#xff0c;可以方便地实现温度监测功能。本文将详细介绍如何利用STM32内置温度传感器实现温度监测系统&#xff0c;并提供相应的示例代码。 一、硬…