最多 K 次交换相邻数位后得到的最小整数

题目链接

视频链接

给你一个字符串 num 和一个整数 k 。其中,num 表示一个很大的整数,字符串中的每个字符依次对应整数上的各个 数位 。

你可以交换这个整数相邻数位的数字 最多 k 次。

请你返回你能得到的最小整数,并以字符串形式返回。

 

示例 1:

 

输入:num = "4321", k = 4
输出:"1342"
解释:4321 通过 4 次交换相邻数位得到最小整数的步骤如上图所示。
示例 2:

输入:num = "100", k = 1
输出:"010"
解释:输出可以包含前导 0 ,但输入保证不会有前导 0 。
示例 3:

输入:num = "36789", k = 1000
输出:"36789"
解释:不需要做任何交换。
示例 4:

输入:num = "22", k = 22
输出:"22"
示例 5:

输入:num = "9438957234785635408", k = 23
输出:"0345989723478563548"

 

这个题首先用贪心的思路来看的话,那么第一位如果能放数组中最小的那肯定是放数组中最小的(能放的意思是最小的下标-i>=k)

所以你就要把每一个数的下标处理出来,然后对于第i位从0-9枚举,如果下标p-i>=k那么就把这个数放在哪里,然后让i到p的所有数

的下标都加一,这个可以用树状数组实现

那么在程序中为什么要add(1,1),add(t,-1)呢?因为它都pop掉了所以没有影响

class Solution {
public:
    int n;
    vector<int>c;
    int lowbit(int x){
        return x&-x;
    }
    void add(int x,int v){
        for(int i=x;i<=n;i+=lowbit(i)){
            c[i]+=v;
        }
    }
    int get_sum(int x){
        int ans=0;
        for(int i=x;i;i-=lowbit(i)){
            ans+=c[i];
        }
        return ans;
    }
    string minInteger(string num, int k) {
        n=num.size();
        c.resize(n+1);
        num=' '+num;
        queue<int>q[10];
        for(int i=1;i<=n;i++){
            q[num[i]-'0'].push(i);
        }
        string ans;
        for(int i=1;i<=n;i++){
            for(int j=0;j<10;j++){
                if(q[j].size()){
                    int t=q[j].front();
                    int pos=t+get_sum(t);
                    if(pos-i<=k){
                        k-=(pos-i);
                        ans+=to_string(j);
                        q[j].pop();
                        add(1,1);
                        add(t,-1);
                        break;
                    }
                }
            }
        }
        return ans;
    }
};

 

posted @ 2021-05-04 20:02  lipu123  阅读(94)  评论(0)    收藏  举报