【算法】单调栈题单——字典序最小⭐(一种类型的模板题)

news2024/11/18 7:48:16

文章目录

  • 题目列表
    • 316. 去除重复字母⭐⭐⭐⭐⭐(类型题模板:单调栈,字典序最小)
    • 221021天池-03. 整理书架(保留数量为 limit 的字典序最小)
    • 402. 移掉 K 位数字(最多删除 k 次 + 前导零的处理)
    • 321. 拼接最大数🚹🚹🚹🚹🚹(繁琐)(分成两组+合并)💩
  • 相关链接

题目列表

从第一题模板题入手。

316. 去除重复字母⭐⭐⭐⭐⭐(类型题模板:单调栈,字典序最小)

https://leetcode.cn/problems/remove-duplicate-letters/description/

在这里插入图片描述
注意:该题与 316 https://leetcode.cn/problems/remove-duplicate-letters/ 相同

冷静分析,先去掉一个字符,该去掉哪一个? 为了字典序越小,肯定要越往前的字符越小越好,那么就应该将最靠前的,且满足s[i]>s[i+1]的那个s[i]删掉即可。

怎么模拟多次这个过程呢?由于最先被删掉的一定更靠前,所以可以使用单调栈从前到后维护保留下来的字符。

除此之外,

  1. 要求每种原来就有的字符至少会保留下来一次,因此如果之后没有这种字符了,那么就不应该将其pop出栈。
  2. 如果一个字符已经在栈中了,那么后续的字符就不需要再加入栈了。

可以直接使用StringBuilder作为栈。

class Solution {
    public String removeDuplicateLetters(String s) {
        int[] cnt = new int[128];
        for (char ch: s.toCharArray()) cnt[ch]++;   // 记录各个字符剩余的数量
        StringBuilder ans = new StringBuilder();    // StringBuilder可以当栈使用
        for (char ch: s.toCharArray()) {
            cnt[ch]--;                              // 将剩余数量-1
            if (ans.indexOf(String.valueOf(ch)) != -1) continue;         // 如果前面已经有ch了,后面不需要再有了
            // 将stk中比当前ch更大且后面还有剩余的字符pop出去
            while (ans.length() > 0 && ch <= ans.charAt(ans.length() - 1) && cnt[ans.charAt(ans.length() - 1)] > 0) {
                ans.deleteCharAt(ans.length() - 1);
            }
            ans.append(ch);
        }
        return ans.toString();
    }
}

也可以使用栈,再转换成字符串。

class Solution {
    public String removeDuplicateLetters(String s) {
        int[] cnt = new int[128];
        for (char ch: s.toCharArray()) cnt[ch]++;   // 记录各个字符剩余的数量
        Deque<Character> stk = new ArrayDeque<>();
        for (char ch: s.toCharArray()) {
            cnt[ch]--;                              // 将剩余数量-1
            if (stk.contains(ch)) continue;         // 如果前面已经有ch了,后面不需要再有了
            // 将stk中比当前ch更大且后面还有剩余的字符pop出去
            while (!stk.isEmpty() && ch <= stk.peek() && cnt[stk.peek()] > 0) {
                stk.pop();
            }
            stk.push(ch);
        }
        // 将栈中的结果转成String返回
        StringBuilder ans = new StringBuilder();
        while (!stk.isEmpty()) ans.append(stk.pop());
        return ans.reverse().toString();
    }
}

221021天池-03. 整理书架(保留数量为 limit 的字典序最小)

https://leetcode.cn/contest/tianchi2022/problems/ev2bru/

在这里插入图片描述
提示:

1 <= order.length <= 10^5
1 <= limit <= 10
1 <= order[i] <= 10^6

class Solution {
    public int[] arrangeBookshelf(int[] order, int limit) {
        Deque<Integer> stk = new ArrayDeque<>();
        // 分别记录剩余的数量,在栈中的数量
        Map<Integer, Integer> cnt_residue = new HashMap<>(), cnt2 = new HashMap<>();
        for (int x: order) cnt_residue.merge(x, 1, Integer::sum);
        for (int x: order) {
            cnt_residue.merge(x, -1, Integer::sum);
            if (cnt2.getOrDefault(x, 0) >= limit) continue;     // 如果栈中已经有足够的x了,就不再添加进去
            // 要求栈中的元素+剩余的元素>limit才会被弹出
            while (!stk.isEmpty() && x < stk.peek() && cnt_residue.get(stk.peek()) + cnt2.getOrDefault(stk.peek(), 0) > limit) {
                cnt2.merge(stk.peek(), -1, Integer::sum);
                stk.pop();
            }
            stk.push(x);
            cnt2.merge(x, 1, Integer::sum);
        }
        int n = stk.size();
        int[] ans = new int[n];
        for (int i = n - 1; i >= 0; --i) {
            ans[i] = stk.pop();
        }
        return ans;
    }
} 

402. 移掉 K 位数字(最多删除 k 次 + 前导零的处理)

https://leetcode.cn/problems/remove-k-digits/description/

在这里插入图片描述

跟之前题目的区别在于,最多删除k次。
以及0可以不删,留着当前导零直接去除。

class Solution {
    public String removeKdigits(String num, int k) {
        Deque<Character> stk = new ArrayDeque<>();
        for (char x: num.toCharArray()) {
            while (!stk.isEmpty() && x < stk.peek() && k > 0) {
                stk.pop();
                k--;
            }
            stk.push(x);
        }
        // 如果还有没用的k,从后往前删除
        while (!stk.isEmpty() && k-- > 0) stk.pop();
        if (stk.size() == 0) return "0";    
        StringBuilder ans = new StringBuilder();
        while (!stk.isEmpty()) ans.append(stk.pop());
        // 去除前导零
        while (ans.length() > 1 && ans.charAt(ans.length() - 1) == '0') ans.deleteCharAt(ans.length() - 1);
        return ans.reverse().toString();
    }
}

321. 拼接最大数🚹🚹🚹🚹🚹(繁琐)(分成两组+合并)💩

https://leetcode.cn/problems/create-maximum-number/description/

在这里插入图片描述

class Solution {
    public int[] maxNumber(int[] nums1, int[] nums2, int k) {
        int m = nums1.length, n = nums2.length;
        int[] maxSubSequence = new int[k];
        int start = Math.max(0, k - n), end = Math.min(k, m);
        for (int i = start; i <= end; ++i) {
            int[] subSequence1 = maxSubSequence(nums1, i);
            int[] subSequence2 = maxSubSequence(nums2, k - i);
            int[] curMaxSubSequence = merge(subSequence1, subSequence2);
            if (compare(curMaxSubSequence, 0, maxSubSequence, 0) > 0) {
                System.arraycopy(curMaxSubSequence, 0, maxSubSequence, 0, k);
            }
        }
        return maxSubSequence;
    }

    // 求最大子序列
    public int[] maxSubSequence(int[] nums, int k) {
        int n = nums.length;
        int[] stk = new int[k];
        int top = -1, remain = n - k;
        for (int i = 0; i < n; ++i) {
            int num = nums[i];
            while (top >= 0 && num > stk[top] && remain > 0) {
                top--;
                remain--;
            }
            if (top < k - 1) {
                stk[++top] = num;
            } else {
                --remain;
            }
        }
        return stk;
    }

    // 合并两个子序列
    public int[] merge(int[] subSequence1, int[] subSequence2) {
        int x = subSequence1.length, y = subSequence2.length;
        if (x == 0) return subSequence2;
        if (y == 0) return subSequence1;
        int mergeLength = x + y;
        int[] res = new int[mergeLength];
        int index1 = 0, index2 = 0;
        for (int i = 0; i < mergeLength; ++i) {
            if (compare(subSequence1, index1, subSequence2, index2) > 0) {
                res[i] = subSequence1[index1++];
            } else {
                res[i] = subSequence2[index2++];
            }
        }
        return res;
    }

    // 比较两个子序列的大小
    public int compare(int[] subSequence1, int index1, int[] subSequence2, int index2) {
        int x = subSequence1.length, y = subSequence2.length;
        while (index1 < x && index2 < y) {
            int diff = subSequence1[index1] - subSequence2[index2];
            if (diff != 0) return diff;
            index1++;
            index2++;
        }
        return (x - index1) - (y - index2);
    }
}

相关链接

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

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

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

相关文章

从0开始学习JavaScript--JavaScript 单元测试

JavaScript单元测试是保障代码质量和可维护性的关键步骤之一。通过编写和运行单元测试&#xff0c;开发者可以确保代码在不断迭代的过程中依然具有正确的行为。本文将深入探讨JavaScript单元测试的核心概念、工具使用和最佳实践&#xff0c;并通过丰富的示例代码演示其实际应用…

mac 系统 vmware 安装centos8

选择镜像 安装系统 依次设置有告警的项目 设置用户名密码 设置root密码 重启系统 重启成功进入下面界面 勾选&#xff0c;点击done 点击箭头所指按钮 输入密码登录 安装成功了 设置网络 打开终端 切换root用户 输入下面指令 su root 输入root的密码 安装git

振动温度一体式传感器的工作原理及其在设备状态监测中的作用

振动温度一体式传感器是一种先进的监测设备&#xff0c;可以同时测量和监测目标物体的振动和温度信息。它结合了振动传感技术和温度传感技术&#xff0c;为工业领域提供了全面而高效的设备状态监测解决方案。在振动温度一体式传感器中&#xff0c;有线和无线两种类型分别在设备…

[github全教程]github版本控制最全教学------- 大厂找工作面试必备!

作者&#xff1a;20岁爱吃必胜客&#xff08;坤制作人&#xff09;&#xff0c;近十年开发经验, 跨域学习者&#xff0c;目前于新西兰奥克兰大学攻读IT硕士学位。荣誉&#xff1a;阿里云博客专家认证、腾讯开发者社区优质创作者&#xff0c;在CTF省赛校赛多次取得好成绩。跨领域…

iOS简单理解区分MVC、MVP、MVVM

MVC、MVP、MVVM 前言 这篇文章简单介绍MVC、MVP和MVVM三种架构&#xff0c;并配上一个简单的Swift demo来区分MVC和MVVM两种架构。 MVC 传统MVC 下图是传统结构MVC&#xff0c;可以看到这种结构是紧耦合的&#xff0c;不推荐使用。 苹果的MVC 如下图&#xff0c;这是苹果…

【翻译】直流电动机的控制

直流电&#xff08;DC&#xff09;电机由于其转矩易于控制&#xff0c;速度控制范围广&#xff0c;已广泛应用于可调速驱动或可变转矩控制中。然而&#xff0c;直流电机有一个主要的缺点&#xff0c;即它们需要机械装置&#xff0c;如换向器和刷子来连续旋转。这些机械部件需要…

windows配置go调用python的编译环境

go是支持调用python代码的&#xff0c;之前写了几篇linux的部署教程&#xff0c;因为觉得windows的不复杂就没有写&#xff0c;结果今天新部署一个Windows的环境&#xff0c;有些步骤想不起来了&#xff0c;好记性不如烂笔头&#xff0c;还是记录一下吧。 这些是之前写的linux…

FlowJo软件的简单介绍 掌控流式细胞分析的科技巨匠 FlowJo10

FlowJo 10 for Mac是一款强大的流式细胞数据分析软件&#xff0c;具有以下功能&#xff1a; 数据导入与预处理&#xff1a;FlowJo 10可以轻松导入各种类型的流式细胞数据&#xff0c;并对数据进行预处理&#xff0c;包括去噪、背景校正等&#xff0c;以确保数据的准确性和可靠…

STM32F407-14.3.9-01输出比较模式

输出比较模式 此功能用于控制输出波形&#xff0c;或指示已经过某一时间段。 当捕获/比较寄存器与计数器之间相匹配时&#xff0c;输出比较功能&#xff1a; ● 将为相应的输出引脚分配一个可编程值&#xff0c;该值由输出比较模式&#xff08;TIMx_CCMRx 寄存器中的 OCxM⑦…

[网鼎杯 2020 青龙组]singal 1

前言 在主函数中找到了一个vm的译码器&#xff0c;译码器主要是解释传入的opcode&#xff0c;然后对我们输入的字符操作&#xff0c;这里我们发现他是单字节比较的&#xff0c;方法很多可以使用单字节映射&#xff0c;也可以是使用符号化执行&#xff0c;当然也可以硬着头皮去…

Docker 环境中 Spring Boot 应用的 Arthas 故障排查与性能优化实战

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 仓库主页&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 欢迎点赞…

EasyExcel两行表头

例子&#xff1a; 代码&#xff1a; StorageService localStorageService storageFactory.getLocalStorageService();String path "";// 文件信息String dateTime DateUtils.formatTimestampToString(new Date());String title "xxx统计";String fil…

TZOJ 1379 C语言合法标识符

答案&#xff1a; #include <stdio.h> #include <string.h> int main() {char arr[60];int n 0, i 0, num 0, flag;scanf("%d", &n);getchar(); //读取回车键while (n--) //循环N次{gets(arr);num strlen(arr); //num为字符串长度flag 1; …

Echarts大屏可视化_05 折线图的定制开发

继续跟着pink老师学习Echarts相关内容&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 折线图1 1.引入 折线图选取示例地址 标题没有用到就给他删了 直接引入 注意这里是line下面的chart 获取dom元素一定不…

java餐饮刀削面快餐店点餐服务系统springboot+jsp

网上点餐省去了客户很多不必要的时间和麻烦&#xff0c;给商家带来更多利益。同时&#xff0c;网上点餐可以辅助餐饮企业营销。传统的点餐是需要配备一个专业的服务员负责菜品介绍并记录顾客点单&#xff0c;确认后上交至后台厨房&#xff0c;厨房根据菜品种类安排做菜顺序最终…

Spring 多数据源搭建

目录 前言 正文 1.Druid 介绍和使用 2.其他多数据源解决方案 总结 前言 对于复杂的业务和项目&#xff0c;可能在一个单体项目中存在需要连接多个数据库的情况。这时&#xff0c;就会使用到多数据源&#xff0c;实际中遇到的可能性比较大。 正文 如果一个项目中需要连…

Unity Image - 镜像

1、为什么要使用镜像 在游戏开发过程中&#xff0c;我们经常会为了节省 美术图片资源大小&#xff0c;美术会将两边相同的图片进行切一半来处理。如下所示一个按钮 需要 400 * 236&#xff0c;然而美术只需要切一张 74*236的大小就可以了。这样一来图集就可以容纳更多的图片。…

Centos7使用阿里云镜像加速服务安装Docker

文章目录 一、前提说明二、安装docker1、创建docker文件夹2、安装所需的软件包3、设置Docker仓库4、安装docker5、启动验证使用阿里云镜像加速服务 三、卸载docker 一、前提说明 需要先安装好虚拟机&#xff0c;可以查看这篇https://blog.csdn.net/qq_36433289/article/detail…

Docker的常用基本命令(基础命令)

文章目录 1. Docker简介2. Docker环境安装Linux安装 3. 配置镜像加速4. Docker镜像常用命令列出镜像列表搜索镜像下载镜像查看镜像版本删除镜像构建镜像推送镜像 5. Docker容器常用命令新建并启动容器列出容器停止容器启动容器进入容器删除容器&#xff08;慎用&#xff09;查看…

Java-easyExcel入门教程

文章目录 前言一、简介二、使用步骤1. 引入依赖2. 前提准备3. 实现导出4. 实现导入 三、我所遇到的问题四、总结 前言 在日常开发中经常会遇到一些 excel 表导入导出的需求&#xff0c;以往会使用 POI 封装成工具类来处理这些导入导出的需求&#xff0c;但是 POI 在导入大文件…