你管这叫字典树?!拼多多笔试3|刷题打卡

129 阅读1分钟

掘金团队号上线,助你 Offer 临门! 点击 查看详情

一、题目描述:

image.png

二、思路分析:

这题最简单思路是递归加遍历,因为字典序所以可以考虑扔优先队列时

但是这样会超时

我们发现,可以将list转换为树的结构,

image.png

进行大幅度剪枝,需要考虑的是如何确定是否在当前节点的子树中,如果在,就往下遍历一个节点(指能遍历a就遍历a,否则则是b)。如果不再则说明在其兄弟节点,那么则需要代表a的节点数量++(回到父节点),代表b的数量--(进入兄弟节点)。

三、AC 代码:

#include <iostream>
#include <string>
#include <map>
using namespace std;
map<pair<int,int>,unsigned long long> ma;
 
unsigned long long f(int m,int n)
{
    if(ma.count({m,n}))return ma[{m,n}];
    if(!m)ma[{m,n}]=n;
    else if(!n)ma[{m,n}]=m;
    else ma[{m,n}]=f(m-1,n)+f(m,n-1)+2;
    return ma[{m,n}];
}
 
int main()
{
    long long k;
    int n,m;
    cin>>n>>m>>k;
    string cur="a";
    n--;
    k--;
    while(k>0&&(m||n))
    {
        unsigned long long step=f(n,m)+1;//子树的个数
        if(step>k)//k在子树中
        {
            k--;
            if(n)
            {
                cur+="a";
                n--;
            }else{
                cur+="b";
                m--;
            }
        }else{//k不在子树中,在下一个子树里
             k-=step;
             n++;
             m--;
             cur.back() = 'b';
        }
    }
    cout<<cur<<endl;
    return 0;
}

四、总结:

在实际实现中并不一定要通过树来存储,可以通过map也好,二维数组也好。

一般就算想到字典树第一反应也是构建这个字典树,而不是假想出字典树并在其上进行操作,本题天马行空很有东西。