【LeetCode】402、移除K位数字

1、移除K位数字

题目:402. 移掉K位数字

题目描述:

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

示例 :

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

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

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

解题思路:基于单调栈的贪心算法

  对于两个长度相同的数字,其最左边的数字决定了这两个数字的大小,左边的数字越小,数字也越小,比如如果由相同的元素组成的数字,升序序列是最小的。所以我们的想法是尽可能地使左边的数字小

  所以,给定一个数字序列[a,b,c,d,e,f],如果数字b小于其左邻居 a,则我们应该删除左邻居a,以获得最小结果。

  对于每个数字,如果该数字小于栈顶部,即该数字的左邻居,则弹出堆栈,即删除左邻居。否则,我们把数字推到栈上。
重复上述步骤,直到任何条件不再适用,例如堆栈为空(不再保留数字)。或者已经删除了 k 位数字。

  同时,这里需要注意一些特殊情况:

  1、如果整个序列是单增的,我们会发现左邻居永远小,所以应该删除掉末尾的k个数字即可。

  2、在完成整个循环后,栈中弹出的数字是逆序的,需要反转,需要注意的是结果可能出现前导零,需要考虑到这种情况,将前导零删除。

代码实现:

class Solution {
    public String removeKdigits(String num, int k) {
        //基于单调栈的贪心思想
        if(k==0)
            return num;
        if(num.length()==0 || k>=num.length())
            return "0";
        
        Stack<Character> stack=new Stack<>();  //维护一个单调栈

        for(int i=0;i<num.length();i++){
            char c=num.charAt(i);
            while(!stack.isEmpty() && stack.peek()>c && k>0 ){  
                stack.pop();  //左边的大则删除,本质是贪心
                k--;
            }
            stack.push(c);
        }

        //特别注意:如果没有删够k次,说明剩下的是单调不减的,则从末尾删除即可
        for(int i=0;i<k;i++)  //剩余多少次由k决定
            stack.pop();

        //最后将栈中的元素弹出并反转即可
        StringBuffer str=new StringBuffer();
        while(!stack.isEmpty()){
            str.append(stack.pop());
        }

        str=str.reverse(); //反转

        //去除前导0
        int index=0;
        while(index<str.length() && str.charAt(index)=='0')
            index++;
        
        String res=str.toString().substring(index);
        
        return res.length()==0?"0":res;
    }
}

2、字典序最大的子序列

题目描述:

  给定⼀个字符串,得到它字典序最⼤的⼦序列。(换言之,也就是删除⼀些字符,使得剩下的字符构成的字符串字典序是最⼤的)

解题思路:

  两个字符串相比,字典序的大小首先是对排在前列的字符进行比较,越靠前的字符越大,整体的字典序就越大,因此,要想字典序最大,应该将其变为一个单调递减的子序列

  因此,这和上一题实际上类似的,只是没有了删除k次的限制,同样应该利用一个单调栈,当栈顶数字小于当前考察的元素时,即将其栈顶数字删除,最后在栈中形成一个单调递减(严格来说是单调不增)的子序列。

代码实现

  与上题代码基本类似,核心在于基于单调栈的贪心思想,越靠前的越大越好。

posted @ 2020-03-24 18:05  gzshan  阅读(971)  评论(0编辑  收藏  举报