难度:中等。
标签:贪心,单调栈,字符串。
用贪心的思想,反过来取出n-k个数字,使得数字最小。
取第i个数字时,判断的范围是从取的上一个数字的索引的下一个数开始,到num中留有[n - k - i - 1]个数字结束,找出这个范围内最小的数(索引为min_idx),就是当前取的数字。
下一个要取的数字就从min_idx开始判断。
正确解法:
class Solution {
public:
string removeKdigits(string num, int k) {
int n = num.length();
if(k >= n)return "0";
string ans = "";
int begin = 0;
for(int i = 0; i < n - k; ++i){
char min_num = num[begin];
int min_idx = begin;
while(begin < n){
if(min_num > num[begin]){
min_num = num[begin];
min_idx = begin;
}
if(n - begin - 1 == n - k - i - 1){
break;
}
begin++;
}
if(!(ans.size() == 0 && num[min_idx] == '0'))ans += num[min_idx];
begin = min_idx + 1;
}
if(ans == "")return "0";
return ans;
}
};
结果:
题解使用贪心+单调栈的做法。
循环判断,若当前元素大于栈顶元素,且还有数字可以去除,则将栈顶元素pop出,当前元素加入栈顶。
遍历完数组后,该去掉的元素k仍大于0,则去掉栈顶k个元素,从栈底到栈顶得到的序列就是所求结果。
由于这样需要反转栈,直接用一个vector来模拟栈。
正确解法:
class Solution {
public:
string removeKdigits(string num, int k) {
int n = num.length();
if(k >= n)return "0";
string ans = "";
vector<char> stk;
for(auto& digit : num){
while(stk.size() > 0 && stk.back() > digit && k){
stk.pop_back();
k--;
}
stk.emplace_back(digit);
}
while(k > 0){
k--;
stk.pop_back();
}
int flag = 1;
for(auto& digit : stk){
if(digit == '0' && flag)continue;
else{
flag = 0;
ans.push_back(digit);
}
}
if(ans == "")return "0";
return ans;
}
};
时间复杂度和空间复杂度都是O(n)。
结果: