2023-07-14 Today's second question-good question

Link:

402. Remove K digits

Title meaning:

A non-negative integer, find the minimum value after deleting k digits

untie:

If you want the number to be the smallest, the core is to let the high bit be the smallest first, and then consider the following numbers

Solution 1 Prototype: (TLE LG=1E5 num="5E4 1 append 5E4 2" K=5E4)

Maintain a number of remaining selectable numbers and a number of numbers that are still needed to obtain a range of options, and each time get the smallest number from the range of options as the highest digit, and then update the number of remaining numbers that can be selected and the number that is still needed number of digits

Solution 1 optimization:

The main reason for timeout is that to get the smallest number in the range, you need to traverse the entire range. Once the smallest number is too far ahead, you have to return to the front position (a bit like the shortcoming of string violence matching, clam), so I wrote a Prefix, so that the minimum number can be judged within 10 times, and when this number is encountered directly during traversal, the number of remaining optional numbers and the number of numbers still needed are updated, and the next number is found

Solution 2 monotonic stack:

According to the sliding window idea, case 1: num1432219 k3 so keep 7-3=4 digits

1432 + 2 -> 1322 + 1 -> 1221 + 9 -> 1219Delete the largest number in the window every time , if you search in the window every time, it becomes the same as solution 1

So the main point is that if there are deletion times and the last one is smaller than the previous one, delete the previous one first (at the same time, since the traversal process is from front to back, the previous numbers are high, which is equivalent to replacing the high number with the big one. is small), that is, a monotonic stack from small to large

Finally, if there are remaining deletion times, it must be deleted from the back, because this step is to delete numbers that exceed the required number of digits, and the number at the back is larger

Actual code:

Solution 1 with prototype:

#include<iostream>
#include<cstring>
using namespace std;
const int Nmax=1E5+7;
int arr[10][Nmax];
char get_mao(int left,int right)
{
    //cout<<"left:"<<left<<" right:"<<right<<endl;
    int temp=0; 
    for(int i=0;i<10;i++)
    {
        if(left) temp=arr[i][right]-arr[i][left-1];
        else temp=arr[i][right];
        
        if(temp) return char('0'+i);
    }
    return -1;
}
string removeKdigits(string num, int k)
{
    string temp,ans;int lg=num.length();
    if(k>=lg) return string("0");
    for(int i=0;i<lg;i++)
    {
        for(int j=0;i && j<10;j++)
        {
            arr[j][i]=arr[j][i-1];
        }
        arr[num[i]-'0'][i]++;
    }
    int last=lg,need=lg-k;//last 剩余数字 need 所需数字
    char mao=get_mao(0,0+k);
    for(int i=0;i<lg;i++)
    {
        if(num[i]==mao)
        {
            temp.push_back(mao);
            last=lg-i-1;need--;
            mao=get_mao(i+1,i+last-need+1);
            if(!need) break;
            //cout<<i<<":"<<temp<<endl;
        }
    }
    
    bool zt=1;
    for(auto ch:temp)
    {
        if(zt && ch=='0') continue;
        if(zt && ch!='0') zt=0;
        
        ans.push_back(ch);
    }
    return ans.empty()?string("0"):ans;
}
int main()
{
    string num;cin>>num;
    int k;cin>>k;
    
    string ans=removeKdigits(num,k);
    cout<<ans<<endl;
    return 0;
}

/* 原型 TLE LG=1E5 num="1*5E4 append 2*5E4" K=5E4
string removeKdigits(string num, int k)
{
    string temp,ans;int lg=num.length();
    if(k>=lg) return string("0");
    int last=lg,need=lg-k,mao=0;//last 剩余数字 need 所需数字 mao所选最小数字位置 
    for(int i=0;i<lg;i++)
    {
        //cout<<"doing-"<<i<<":"<<mao<<" "<<need<<endl;
        last=lg-i;
        if(num[i]<num[mao]) mao=i;//更新最小数字
        if(last==need)//剩余数字等于所需数字时,选取前面遍历到的最小数字作为该位数字 
        {
            //cout<<i<<" "<<mao<<endl;
            temp.push_back(num[mao]);need--;
            i=mao++;
        }
    }
    //cout<<temp<<endl;
    bool zt=1;
    for(auto ch:temp)
    {
        if(zt && ch=='0') continue;
        if(zt && ch!='0') zt=0;
        
        ans.push_back(ch);
    }
    return ans.empty()?string("0"):ans;
}*/

Solution 2:

#include<iostream>
#include<cstring>
using namespace std;
string removeKdigits(string num, int k)
{
    string temp,ans;int lg=num.length();
    if(k>=lg) return string("0");
    for(int i=1;i<num.length();i++)
    {
        if(k && num[i]<num[i-1])//单调 
        {
            num.erase(i-1,1);//删除 
            k--;i=max(0,i-2);//复位 
        }
        //cout<<num<<endl;
    }
    //剩余次数 
    while(k)
    {
        num.erase(num.length()-1,1);
        k--;
    }
    //去前导0 
    bool zt=1;
    for(auto ch:num)
    {
        if(zt && ch=='0') continue;
        if(zt && ch!='0') zt=0;
        
        ans.push_back(ch);
    }
    return ans.empty()?string("0"):ans;
}
int main()
{
    string num;cin>>num;
    int k;cin>>k;
    
    string ans=removeKdigits(num,k);
    cout<<ans<<endl;
    return 0;
}

limit:

  • 1 <= k <= num.length <= 105
  • numConsists of only a few digits (0 - 9)
  • Do not contain any leading zeros other than 0 itselfnum

Guess you like

Origin blog.csdn.net/Fei_WuYan/article/details/131733001