牛客 小米校招 最大新整数 单调栈
题目描述
有一十进制正整数,移除其中的 K 个数,使剩下的数字是所有可能中最大的。
假设:
字符串的长度一定大于等于 K
字符串不会以 0 开头
输入描述:
一行由正整数组成的数字字符串,和一个正整数 K,两个数据用空格隔开,如:1432219 3。
字符串长度不超过2000,K<=2000。
输出描述:
移除 K 位后可能的最大的数字字符串。
如 1432219
移除 1, 2, 1
这 3 个数字后得到 432
,为所有可能中的最大值。
示例1
输入
复制
1432219 3
输出
复制
4329
可以发现 :
- 一个数字数组可以划分成很多个子数组,这些子数组可能
单调增
单调减
或者平滑不变
- 如果这个数 num=12349685以
递增
子数组开头,则只要还可以删除数字,删开头
一定最优 - 如果这个数 num=43217892以
递减
子数组开头,且能删的个数小于4
,则开头一定不能删
应该删除 321则三个数 - 只要还能删,我们就必须留下最长
单调减
序列,一定是最优答案
考虑单调栈(看别人的代码才知道的,一开始考虑贪心自闭了很久)
- 只要当前数字 num[i]比栈顶大,并且还能删除,则删除栈顶,并把 num[i]入栈
- 当 for完整个数字数组还有可以删除的个数 k,则进行 k次
弹栈
- 最后 , 把栈内的数字翻转 reverse就是答案
//设数字为24593215
//如果[0,K]是递增的,删掉[0,cnt(cnt<K)]会使得答案增大
//找到所有递增序列,删掉
string str;
cin >> str >> K;
stack<char> stk;
for(auto ch : str) { //把每个数字和栈顶比较
while(stk.size() && stk.top() < ch && K) { //只要还能删除 且 栈顶小于num[i]就退栈
stk.pop();
K --;
}
stk.push(ch); //num[i]入栈
}
string ans;
while(K--) { //删到最后还能删,继续退栈
stk.pop();
}
while(!stk.empty()) {
ans.push_back(stk.top());
stk.pop();
}
reverse(ans.begin(), ans.end()); //记得翻转
cout << ans << endl;
完整代码
#define debug
#ifdef debug
#include <time.h>
#include "/home/majiao/mb.h"
#endif
#include <iostream>
#include <algorithm>
#include <vector>
#include <string.h>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <math.h>
#define MAXN ((int)1e5+7)
#define ll long long int
#define INF (0x7f7f7f7f)
#define fori(lef, rig) for(int i=lef; i<=rig; i++)
#define forj(lef, rig) for(int j=lef; j<=rig; j++)
#define fork(lef, rig) for(int k=lef; k<=rig; k++)
#define QAQ (0)
using namespace std;
#define show(x...) \ do { \ cout << "\033[31;1m " << #x << " -> "; \ err(x); \ } while (0)
void err() { cout << "\033[39;0m" << endl; }
template<typename T, typename... A>
void err(T a, A... x) { cout << a << ' '; err(x...); }
namespace FastIO{
char print_f[105];
void read() {}
void print() { putchar('\n'); }
template <typename T, typename... T2>
inline void read(T &x, T2 &... oth) {
x = 0;
char ch = getchar();
ll f = 1;
while (!isdigit(ch)) {
if (ch == '-') f *= -1;
ch = getchar();
}
while (isdigit(ch)) {
x = x * 10 + ch - 48;
ch = getchar();
}
x *= f;
read(oth...);
}
template <typename T, typename... T2>
inline void print(T x, T2... oth) {
ll p3=-1;
if(x<0) putchar('-'), x=-x;
do{
print_f[++p3] = x%10 + 48;
} while(x/=10);
while(p3>=0) putchar(print_f[p3--]);
putchar(' ');
print(oth...);
}
} // namespace FastIO
using FastIO::print;
using FastIO::read;
int n, m, Q, K;
bool up[MAXN], vis[MAXN];
int main() {
#ifdef debug
freopen("test", "r", stdin);
clock_t stime = clock();
#endif
//设数字为24593215
//如果[0,K]是递增的,删掉[0,cnt(cnt<K)]会使得答案增大
//找到所有递增序列,删掉
string str;
cin >> str >> K;
stack<char> stk;
for(auto ch : str) {
while(stk.size() && stk.top() < ch && K) {
stk.pop();
K --;
}
stk.push(ch);
}
string ans;
while(K--) {
stk.pop();
}
while(!stk.empty()) {
ans.push_back(stk.top());
stk.pop();
}
reverse(ans.begin(), ans.end());
cout << ans << endl;
#ifdef debug
clock_t etime = clock();
printf("rum time: %lf 秒\n",(double) (etime-stime)/CLOCKS_PER_SEC);
#endif
return 0;
}