题目如下
本题出题人给的官方解答代码有点抽象,这里分享一下我的理解
实际上本题我更认为是数学+思维,没有用到任何算法,就是思维要严谨一些,多一些特判
首先保证特殊样例能过,只有一位数,换言之s的size等于0,直接cout<<0
然后就思考,只删一个数字怎么让留下的最小,比如123和321两个例子,我们很容易发现123中我们删除最后一位,也就是递增的字符数组,我们不用特别管,因为在循环输出的时候让循环次数严格小于s.size() ---也就是删掉一个字符的长度,这样就自然截断了最后一位
而321我们发现高位的数字只要一删除,该数字一定是所有删除一个数后最小的一个情况,比如
312--》12,132--》12,1919810--》119810等等,即当s[i]>s[i+1]时,删掉s[i],删除操作可以让该位置的值更新为-1,输出时遇到-1跳过不输出就行了
接下来是特殊数字的判断,这里笔者也是wa了多次,一步步优化找到特殊案例
对于题目告诉你的9011变为11,我们可以发现当某个位置变为-1不输出时,他的下一位可能时0,所以还要引入特例判断-1的下一位是不是零,这里引入position变量记录可能使首位为零的位置,若9001这样连续出现0的情况,我们需要在发现第一个首位0后让position++看首位0的下一个是否还是0,这样10086这种例子也能过了
最后是10000这样的数据,他输出为空,这个特例要特殊处理,好在处理起来也简单,引入flag变量初始为0,如果有输出变为1,如果循环输出完还是没0(没有输出)就专门输出一个0
这样所有情况就考虑妥当了
ac代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
#define int long long
int n;
string s;
void solve(){
if(s.size()==0)cout<<0;
for(int i=0;i<s.size();i++){
if(s[i]>s[i+1]){
s[i]=-1;
break;
}
}
int position=0,flag=0;
for(int i=0;i<s.size();i++){
if(s[i]==-1){
position++;
continue;
}
if(s[position]=='0'){
position++;
continue;
}
cout<<s[i];
flag=1;
}
if(flag==0) cout<<0;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>s;
solve();
return 0;
}