zyb的面试

今天zyb参加一场面试,面试官听说zyb是ACMer之后立马抛出了一道算法题给zyb:
有一个序列,是1到n的一种排列,排列的顺序是字典序小的在前,那么第k个数字是什么?
例如n=15,k=7, 排列顺序为1, 10, 11, 12, 13, 14, 15, 2, 3, 4, 5, 6, 7, 8, 9;那么第7个数字就是15.
那么,如果你处在zyb的场景下,你能解决这个问题吗?

 
Input
T组样例(T<=100)
两个整数n和k(1<=n<=1e6,1<=k<=n),n和k代表的含义如上文
 
Output
输出1-n之中字典序第k小的数字
 
Sample Input
1 15 7
 
Sample Output
15
 
就是求1-n的字典序排列的第几个
 
一开始用递归来写   果然超时了
#include<bits/stdc++.h>
using namespace std;
//input by bxd
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m)
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s);
#define LL long long
#define REP(i,N)  for(int i=0;i<(N);i++)
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////
#define N 1e6+5

int cnt;
int m;
void f(int n,int t)
{
    if(n>t)
        return;
    ++cnt;
    if(cnt==m){printf("%d
",n);return;}
    rep(i,0,9)
    f(10*n+i,t);
}
int main()
{
    int n;
    int cas;RI(cas);
    while(cas--)
    {
        cnt=0;
        RII(n,m);
        for(int i=1;i<=9;i++)
            f(i,n);
    }
}
View Code

参考大神的方法:

#include<bits/stdc++.h>
using namespace std;
//input by bxd
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m)
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s);
#define LL long long
#define REP(i,N)  for(int i=0;i<(N);i++)
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////

long getCntOfPre(long pre, long n)  // 计算以pre为开头并且小于n的数字的个数
{
    long cnt = 1;
    long p = 10;
    for (; pre*p <= n; p *= 10)
        cnt += min(n, pre*p - 1 + p) - pre*p + 1;
    return cnt;
}

long solve(long n, long m)
{
    long ans = 1;
    while (m != 0)
    {
        long cnt = getCntOfPre(ans, n);
        if (cnt >= m)
        {
            m--;
            if (m == 0)
                break;  //  最终结果
            ans *= 10;      // 对应打头的数乘10,比如:原来是计算10打头的个数,现在要计算100打头的个数(缩小范围)
        }
        else
        {
            m -= cnt;  // 第m个数改为第m-cnt个数
            ans++;    // 对应打头的数加1,比如:原来是计算10打头的个数,现在要计算11打头的个数
        }
    }
    return ans;
}

int main()
{
    long n, m;
    int q;RI(q);
    while (q--)
    {
        RII(n,m);
        cout << solve(n, m) << endl;
    }
    return 0;
}
View Code

标准答案是用十叉树来做

 
 
 
 
 
原文地址:https://www.cnblogs.com/bxd123/p/10560555.html