给定一个以字符串表示的非负整数 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。
分析:
若去掉某一位数字,为了使得到的新数字最小,需要尽可能让得到的新数字优先最高位最小,其次次高位最小,再其次第三位最小。
例如:
一个4位数“ 1***” ,一定比任何“8***”、“ 8***”、…、“ 2***”小!
一个4位数若最高位确定,如“ 51**”一定比任何“ 59**”、“58**”、… 、“ 52**”小!
一个4位数若最高、次高位确定,如“ 531*”一定比任何“ 539*”、“538*”、… 、“ 532*”小!
贪心规律:从高位向低位遍历,如果对应的数字大于下一位数字,则把该位数字去掉,得到的数字最小!我们可以使用栈来实现。
注意:
1.当所有数字都扫描完成后,k仍然>0,应该做怎样的处理?例如: num = 12345,k = 3 时。
2.当数字中有0出现时,应该有怎样的特殊处理?例如: num = 100200, k = 1 时。
#include<iostream>
#include<vector>
#include<string>
#include<queue>
using namespace std;
class Solution{
public:
//移掉k位数字使得到的最小
string removeKdigits(string num, int k) {
vector<int> v; //vector充当栈
string res = "";
for(int i = 0; i < num.length(); i++) {
int number = num[i] - '0';
while(v.size() > 0 && v.back() > number && k > 0) {
v.pop_back(); //栈顶元素出栈
k--;
}
//当number=0时,只有栈中有元素才能入栈
if(number !=0 || v.size() != 0) {
v.push_back(number);
}
}
//所有数字扫描完后,k任然大于0,则出栈k位
while(v.size() != 0 && k > 0) {
v.pop_back();
k--;
}
for(int i = 0; i < v.size(); i++) {
res.append(1,'0' + v[i]); //在res的后面添加1个字符
}
if(res == "") {
res = "0"; //特殊情况
}
return res;
}
//求k位最大的子序列
void removeKdigits2(string num,int k) {
int n = num.length();
if(k >= n) {
cout<<num;
}
vector<int> res;
int pop = n-k; //要移除n-k个数
for(int i = 0; i < n; i++) {
int number = num[i]-'0';
while(!res.empty() && number > res.back() && pop > 0) {
res.pop_back();
pop--;
}
res.push_back(number);
}
res.resize(k);
for(int i = 0; i < k; i++) {
cout<<res[i];
}
cout<<endl;
}
};
int main(void) {
Solution s;
string res = s.removeKdigits("1432219",3);
s.removeKdigits2("10200",3);
cout<<res;
return 0;
}