問題描述
給定一個以字符串表示的非負整數 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。
解題報告
爲了使得剩下的數字最小,最好的策略是儘可能讓高位的數字小一些。
所以維護一個 單調遞增棧
,當前元素小於棧頂元素時,將棧頂元素出棧直到當前元素大於等於棧頂元素【當然這個過程需要保證出棧的元素個數小於等於 k
】。
最後將棧中元素取出【當然需要保證刪除的元素達到 k
,如果當前刪除的元素小於 k
,則依次將棧中元素彈出,直到達到 k
】。
另外需要注意一點是,由於在棧底的是數字的高位,所以在棧爲空時,如果即將入棧的元素爲 0
,那麼跳過入棧操作。
實現代碼
class Solution{
public:
string removeKdigits(string num, int k) {
stack<char> s;
for (int i = 0; i < num.size(); i++)
{
while (!s.empty() && s.top() > num[i] && k)
{
s.pop();
k--;
}
if (s.empty() && num[i] == '0')
continue;//跳過前置0
s.push(num[i]);
}
string result;
while (!s.empty())
{
if (k > 0)//當還要再移除數字的時候:從此時單調遞增棧的top部刪去數字
k--;
else if (k == 0)//當不用再移除數字的時候:把字符串取出來到result
result += s.top();
s.pop();
}
reverse(result.begin(), result.end());//stl中的reverse函數
return result == "" ? "0" : result;
}
};
單調棧其實不一定要新創建一個棧,比如下面這種實現。
class Solution {
public:
string removeKdigits(string num, int k){
string result;
for (int i = 0; i < num.size(); i++){
while (result.size() && k&&result.back() > num[i]){
result.pop_back();
k--;
}
if (result.size() == 0 && num[i] == '0')
continue;
result+=num[i];
}
// 注意:這裏必須同時滿足!result.empty(),因爲有可能因爲前置0的原因而跳過某些元素。前置0放到數字開頭是沒有用途的。
while (k > 0 && !result.empty()){
result.pop_back();
k--;
}
return result == "" ? "0" : result;
}
};