【贪心 单调栈】P1106 删数问题

269 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情

删数问题

题目描述

键盘输入一个高精度的正整数 N(不超过 250 位),去掉其中任意 k 个数字后剩下的数字按原左右次序将组成一个新的非负整数。编程对给定的 N 和 k,寻找一种方案使得剩下的数字组成的新数最小。

输入格式

n(高精度的正整数 )。

k(需要删除的数字个数 )。

输出格式

最后剩下的最小数。

样例 #1

样例输入 #1

 175438 
 4

样例输出 #1

 13

题目大意与解题思路:

题意: 删去k个数字,使剩下的数字最小。

思考: 如果第 i 个数比第 i-1个数大,那么我们称第 i个数可以删掉第 i-1个数。这样,我们就可以采用对于一个数暴力往前跳然后删除的算法。

题解:

这是一个贪心思想,高位尽量选小的,但是顺序又不能改变

所以循环时边界条件不是数的长度,而是长度-还剩的要选的个数

  • 考虑两个数字,高位低的数字会更小,随后保证低位小。
  • 因此采用单调栈维护一个n-k长的上升序列,如果新入栈的数比栈顶小就一直出栈直到不小为止。
  • 因为序列要保证长度,每个数只会入栈一次,出栈就删一个数。不过很有可能没删完就结束了。
  • 循环结束,需要把n-k以上的删完。特
  • 特判下前导0。

举个例子

首先来看一个例子-> 输入n和4

  • n=175438 //删掉7
  • 15438 //删掉5
  • 1438 //删掉4
  • 138 //删掉8
  • 13 //解为13

Code

 #include<bits/stdc++.h>
 using namespace std;
 ​
 ​
 char ans[256];
 int main(){
     string s;
     int k;;
     cin>>s>>k;
     int n = s.size();
     stack<char>st;
     st.push(s[0]);
     int c=0;
     for(int i=1;i<n;i++){
         while(!st.empty()&&st.top()>s[i]&&c<k){
             st.pop();
             c++;
         }
         st.push(s[i]);
     }
     while(c<k){
         st.pop();
         c++;
     }
     c=n-k;
     ans[c--]='\0';
     while(c>=0) ans[c--]=st.top(),st.pop();
     c = 0;
     while(c<n-k-1&&ans[c]=='0') c++;
     printf("%s",ans+c);
     return 0;
 }
 ​