[LeetCode] 402. Remove K Digits 去掉K位數字


 

Given a non-negative integer num represented as a string, remove k digits from the number so that the new number is the smallest possible.

Note:

  • The length of num is less than 10002 and will be ≥ k.
  • The given num does not contain any leading zero.

 

Example 1:

Input: num = "1432219", k = 3
Output: "1219"
Explanation: Remove the three digits 4, 3, and 2 to form the new number 1219 which is the smallest.

 

Example 2:

Input: num = "10200", k = 1
Output: "200"
Explanation: Remove the leading 1 and the number is 200. Note that the output must not contain leading zeroes.

 

Example 3:

Input: num = "10", k = 2
Output: "0"
Explanation: Remove all the digits from the number and it is left with nothing which is 0.

 

這道題讓我們將給定的數字去掉k位,要使得留下來的數字最小,這題跟 LeetCode 上之前那道 Create Maximum Number 有些類似,可以借鑒其中的思路,如果n是 num 的長度,我們要去除k個,那么需要剩下 n-k 個,怎么判斷哪些數字應該去掉呢?首先來考慮,若數字是遞增的話,比如 1234,那么肯定是要從最后面移除最大的數字。若是亂序的時候,比如 1324,若只移除一個數字,移除誰呢?這個例子比較簡單,我們一眼可以看出是移除3,變成 124 是最小。但是怎么設計算法呢,實際上這里利用到了單調棧的思想,可以參見博主之前的一篇總結帖 LeetCode Monotonous Stack Summary 單調棧小結。這里我們維護一個遞增棧,只要發現當前的數字小於棧頂元素的話,就將棧頂元素移除,比如點那個遍歷到2的時候,棧里面有1和3,此時2小於棧頂元素3,那么將3移除即可。為何一定要移除棧頂元素呢,后面說不定有更大的數字呢?這是因為此時棧頂元素在高位上,就算后面的數字再大,也是在低位上,我們只有將高位上的數字盡可能的變小,才能使整個剩下的數字盡可能的小。這里雖然利用了單調棧的思想,但我們並不用真正用棧 stack 的數據結構,直接用個字符串就行了,因為字符串 string 也可以移除末尾字符。我們開始遍歷給定數字 num 的每一位,對於當前遍歷到的數字c,進行如下 while 循環,如果 res 不為空,且k大於0,且 res 的最后一位大於c,那么應該將 res 的最后一位移去,且k自減1。當跳出 while 循環后,我們將c加入 res 中,最后將 res 的大小重設為 n-k。根據題目中的描述,可能會出現 "0200" 這樣不符合要求的情況,所以我們用一個 while 循環來去掉前面的所有0,然后返回時判斷是否為空,為空則返回 “0”,參見代碼如下:

 

解法一:

class Solution {
public:
    string removeKdigits(string num, int k) {
        string res = "";
        int n = num.size(), keep = n - k;
        for (char c : num) {
            while (k && res.size() && res.back() > c) {
                res.pop_back();
                --k;
            }
            res.push_back(c);
        }
        res.resize(keep);
        while (!res.empty() && res[0] == '0') res.erase(res.begin());
        return res.empty() ? "0" : res;
    }
};

 

下面這種方法寫法稍稍不同,在將數字c加入結果 res 的時候提前做一個判斷,假如此時 res 不為空或者數字c不是0,那么才將c加入結果 res 中,這樣就避免了 leading zero。for 循環結束后,不是將結果 resize,而是用一個 while 循環,假如此時 k 還大於0,則將 res 末尾移除k個字符即可,參見代碼如下:

 

解法二:

class Solution {
public:
    string removeKdigits(string num, int k) {
        string res;
        int n = num.size(), keep = n - k;
        for (char c : num) {
            while (k && res.size() && res.back() > c) {
                res.pop_back();
                --k;
            }
            if (res.size() || c != '0') res.push_back(c);
        }
        while (res.size() && k--) res.pop_back();
        return res.empty() ? "0" : res;
    }
};

 

Github 同步地址:

https://github.com/grandyang/leetcode/issues/402

 

類似題目:

Create Maximum Number

Remove Duplicate Letters

 

參考資料:

https://leetcode.com/problems/remove-k-digits/

https://leetcode.com/problems/remove-k-digits/discuss/88708/Straightforward-Java-Solution-Using-Stack

https://leetcode.com/problems/remove-k-digits/discuss/88743/C%2B%2B-6ms-10-lines-solution-with-comments

https://leetcode.com/problems/remove-k-digits/discuss/88660/A-greedy-method-using-stack-O(n)-time-and-O(n)-space

 

LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM