题目描述:

给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小。

注意:

num 的长度小于 10002 且 ≥ k。
num 不会包含任何前导零。
示例 1 :

输入: num = "1432219", k = 3
输出: "1219"
解释: 移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219。
示例 2 :

输入: num = "10200", k = 1
输出: "200"
解释: 移掉首位的 1 剩下的数字为 200. 注意输出不能有任何前导零。
示例 3 :

输入: num = "10", k = 2
输出: "0"
解释: 从原数字移除所有的数字,剩余为空就是0。

思路分析:

对于两个相同长度的数字序列,最左边不同的数字决定了这两个数字的大小,例如,对于 A = 1axxxA=1axxx,B = 1bxxxB=1bxxx,如果 a > ba>b 则 A > BA>B。

基于此,我们可以知道,若要使得剩下的数字最小,需要保证靠前的数字尽可能小

让我们从一个简单的例子开始。给定一个数字序列,例如 425425,如果要求我们只删除一个数字,那么从左到右,我们有 44、22 和 55 三个选择。我们将每一个数字和它的左邻居进行比较。从 22 开始,22 小于它的左邻居 44。假设我们保留数字 44,那么所有可能的组合都是以数字 44(即 4242,4545)开头的。相反,如果移掉 44,留下 22,我们得到的是以 22 开头的组合(即 2525),这明显小于任何留下数字 44 的组合。因此我们应该移掉数字 44。如果不移掉数字 44,则之后无论移掉什么数字,都不会得到最小数。

基于此,我们可以每次对整个数字序列执行一次这个策略;删去一个字符后,剩下的 n-1长度的数字序列就形成了新的子问题,可以继续使用同样的策略,直至删除 k 次。

然而暴力的实现复杂度最差会达到 O(nk)(考虑整个数字序列是单调不降的),因此我们需要加速这个过程。

考虑从左往右增量的构造最后的答案。我们可以用一个栈维护当前的答案序列,栈中的元素代表截止到当前位置,删除不超过 k 次个数字后,所能得到的最小整数。根据之前的讨论:在使用 k 个删除次数之前,栈中的序列从栈底到栈顶单调不降。

因此,对于每个数字,如果该数字小于栈顶元素,我们就不断地弹出栈顶元素,直到

  • 栈为空
  • 或者新的栈顶元素不大于当前数字
  • 或者我们已经删除了 k 位数字

上述步骤结束后我们还需要针对一些情况做额外的处理:

如果我们删除了 m 个数字且 m<k,这种情况下我们需要从序列尾部删除额外的 k−m 个数字。
如果最终的数字序列存在前导零,我们要删去前导零。
如果最终数字序列为空,我们应该返回 0。
最终,从栈底到栈顶的答案序列即为最小数。

考虑到栈的特点是后进先出,如果通过栈实现,则需要将栈内元素依次弹出然后进行翻转才能得到最小数。为了避免翻转操作,可以使用双端队列代替栈的实现。

class Solution {public String removeKdigits(String num, int k) {//维护一个双端队列Deque<Character> deque = new LinkedList<Character>();int leght = num.length();for (int i = 0; i < leght; i++) {char c = num.charAt(i);//当且仅当K>0 并且队尾元素大于要入队的元素的时候就把队尾元素移除掉while (!deque.isEmpty()&& k>0 && deque.peekLast()>c){deque.pollLast();k--;}//如果不大于则直接入队deque.offerLast(c);}//此时如果K还大于0 队列里面的元素已经为单调不降了。则最后依次移除队列尾部剩余的k数次即可,//拿123456728 k=7 举例说明//入队完后 队列里面为1228 此时k=2 所以还需要依次移除尾部2和8  剩余12即为最小for (int i = 0; i < k; i++) {deque.pollLast();}boolean flag =true;StringBuffer res = new StringBuffer();//从队列头部取出所有元素while (!deque.isEmpty()){Character character = deque.pollFirst();//防止前导0 也就是队头第一个元素==0 则需要跳过。if(flag && character=='0'){continue;}flag=false;res.append(character);}//返回结果return res.length()==0?  "0" :res.toString();}
}

复杂度

时间复杂度:O(n),其中 n为字符串的长度。尽管存在嵌套循环,但内部循环最多运行 k 次。对于主循环之外的逻辑,它们的时间复杂度是 O(n),因此总时间复杂度为 O(n)。

空间复杂度:O(n)。栈存储数字需要线性的空间。

LeetCode-402:移除k位数字相关推荐

  1. LeetCode 402. 移掉K位数字 中等难度

    402. 移掉K位数字 题目: 给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小. 注意: num 的长度小于 10002 且 ≥ k. num 不会包含任何前导 ...

  2. Java实现 LeetCode 402 移掉K位数字

    402. 移掉K位数字 给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小. 注意: num 的长度小于 10002 且 ≥ k. num 不会包含任何前导零. 示 ...

  3. LeetCode 402. 移掉K位数字(贪心,单调栈)

    1. 题目 给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小. 注意: num 的长度小于 10002 且 ≥ k. num 不会包含任何前导零. 示例 1 : ...

  4. leetcode 402. 移掉K位数字(贪心算法)

    给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小. 注意: num 的长度小于 10002 且 ≥ k. num 不会包含任何前导零. 示例 1 : 输入: nu ...

  5. C++算法学习(力扣:402. 移掉K位数字)

    给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小. 注意: num 的长度小于 10002 且 ≥ k. num 不会包含任何前导零. 示例 1 : 输入: nu ...

  6. 402. 移掉K位数字(单调栈)

    给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小. 注意: num 的长度小于 10002 且 ≥ k. num 不会包含任何前导零. 示例 1 : 输入: nu ...

  7. 贪心法——LeetCode 402 移除K个数字

    移除K个数字 题目: 给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小. 注意: num 的长度小于 10002 且 ≥ k. num 不会包含任何前导零. 示例 ...

  8. 402. 移掉K位数字 golang

    测试用例 示例 2 : 输入: num = "10200", k = 1 输出: "200" 解释: 移掉首位的 1 剩下的数字为 200. 注意输出不能有任何 ...

  9. 402.移掉K位数字,使得剩下数字最小

    思路 这道题让我们从一个字符串数字中删除 k 个数字,使得剩下的数最小.也就说,我们要保持原来的数字的相对位置不变. 以题目中的 num = 1432219, k = 3 为例,我们需要返回一个长度为 ...

  10. leetcode 402. Remove K Digits | 402. 移掉 K 位数字(单调栈)

    题目 https://leetcode.com/problems/remove-k-digits/ 题解 本题考察对问题的抽象能力,多写几个例子可以发现,这是一个单调栈问题,维护一个单调不减栈. cl ...

最新文章

  1. 2019年2月26日 Unique Email Addresses、To Lower Case、Encode and Decode TinyURL
  2. 基于html的数据库,基于HTML5的本地数据库与服务端数据库的协同研究
  3. 【 Vivado 】输出延迟约束实例
  4. 狄德罗效应下,小程序被“逼”向中心化
  5. 针对监控摄像机(海康、大华等)进行手动录像的录像文件播放器功能设计
  6. 关于站库分离渗透思路总结
  7. python 函数的调用的时候参数的传递_Python Unittest;如何获取调用函数时传递的参数?...
  8. java多线程之hashmap concurrenthashmap的状态同步
  9. 企业贡献开源,其背后的战略动机是什么?
  10. Java语言中的----继承(二)
  11. 如何把vcf文件转换成maf文件格式?vcf2maf一键解决!
  12. opencv之cvtColor()函数
  13. 破解百词斩单词数据之旅
  14. 电脑pin码忘了登录不进系统_忘记计算机 PIN 码怎么办?
  15. 2021年嵌入式校招求职经历
  16. 微信公众号 接口配置
  17. android 9图工具位子,Android自定义9宫格图片视图
  18. c语言位运算负数的实例_负数位运算的右移操作-C语言基础
  19. Kotlin - 面向对象之抽象类与接口
  20. FZU2285 迷宫寻宝

热门文章

  1. bzoj1047/luogu2216 理想的正方形 (单调队列)
  2. stun服务器搭建(coTurn)
  3. phpExcel与jq的ajax
  4. Android开发 更改返回button的图标
  5. php 数组去重且不保留,php数组去重并计数求和如何操作
  6. 动态规划基础——爬楼梯(Leetcode 70)
  7. 怎么看b树是几阶_数据库原理基础:设计B树与B+树的目的以及二者的优劣
  8. 资源丨MySQL故障排查思路方法PPT视频24问答
  9. grpc双向流究竟是什么情况?2段代码告诉你
  10. 带你读AI论文丨用于目标检测的高斯检测框与ProbIoU