LeetCode - 贪心 - 402. 移掉K位数字

402. 移掉K位数字

给定一个以字符串表示的非负整数 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。

简单介绍:
难度:中等
使用语言:JAVA。
这道题来自leetcode题库的贪心算法标签。

解题思路:
首先看题、分析题意:

  1. 暴力枚举肯定会超时,所以要缩短时间
  2. 要求数字最小,即高位越小则整体数值就越小
  3. 从左到右遍历删除,选择最小的组合
  4. 利用栈来实现这种思想

既然,我们已经分析出来题目的关键任务了,下面我们就可以开始思考实现了。
我们采用算法与数据结构的思路来剖析一下这题

数据结构:
要实现对数据的操作,我们要先明确存储数据的数据结构。
LinkedList < Character > Stack - 利用栈来存储

算法

  • 对于每个数字,如果该数字小于栈顶部,即该数字的左邻居,则弹出堆栈,即删除左邻居。否则,我们把数字推到栈上。
  • 我们重复上述步骤,直到任何条件不再适用,例如堆栈为空(不再保留数字)。或者我们已经删除了 k 位数字
    在这里插入图片描述
    特殊情况
  • 当我们离开主循环时,我们删除了 m 个数字,这比要求的要少,即(m<k)。在极端情况下,我们不会删除循环中单调递增序列的任何数字,即 m==0。在这种情况下,我们只需要从序列尾部删除额外的 k-m 个数字。
  • 一旦我们从序列中删除 k 位数字,可能还有一些前导零。要格式化最后的数字,我们需要去掉前导零。
    我们最终可能会从序列中删除所有的数字。在这种情况下,我们应该返回零,而不是空字符串。

代码

class Solution {
  public String removeKdigits(String num, int k) {
    LinkedList<Character> stack = new LinkedList<Character>();
        
    for(char digit : num.toCharArray()) {
      while(stack.size() > 0 && k > 0 && stack.peekLast() > digit) {
        stack.removeLast();
        k -= 1;
      }
      stack.addLast(digit);
    }
        
    /* remove the remaining digits from the tail. */
    for(int i=0; i<k; ++i) {
      stack.removeLast();
    }
        
    // build the final string, while removing the leading zeros.
    StringBuilder ret = new StringBuilder();
    boolean leadingZero = true;
    for(char digit: stack) {
      if(leadingZero && digit == '0') continue;
      leadingZero = false;
      ret.append(digit);
    }
        
    /* return the final string  */
    if (ret.length() == 0) return "0";
    return ret.toString();
  }
}


版权声明:本文为weixin_43583163原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。