UVA 11732 "strcmp()" Anyone?(用数组存储trie树)

本博客详细介绍了如何解决UVA 11732问题,通过利用Trie树(字典树)来优化字符串比较的次数计算。文章解析了比较次数的计算思路,并讨论了使用传统方法和左儿子右兄弟方法构建Trie树的区别,以及在空间效率上的考量。同时,给出了采用左儿子右兄弟方法构建Trie树的代码实现。

题目链接https://vjudge.net/problem/UVA-11732

参考自:liuzibujian 的博客 https://blog.youkuaiyun.com/zengchen__acmer/article/details/24416217

解题思路:

先说求得比较次数的思路,不考虑怎么建字典树:

(1)按照题中给的strcmp函数,for循环中比较一次,如果当前两字符不相同,那么判断if那个句子。

(2)也就是说 在第i位不同,就比较 2*(i-1)+1 = 2*i-1次

(3)那么我们建一颗trie树,每个节点储存当前情况下延伸出去的子节点的个数,记做 trie【i】.sum

遍历当前节点的子节点与当前正在插入的字符,不管如何,该字符和所有子节点储存的字母都会比较一次

设当前节点为U,那么 ans += trie【U】.sum

(4)如果子节点中有和当前插入字符匹配的,设有匹配的那个字符的节点为j,那么聪明的你肯定知道为什么要

ans += trie【j】.sum 了,因为这代表对每个在strcmp函数进行if那个句子的比较的数量

 

理解了思路,那么就要建立trie树,按照https://blog.youkuaiyun.com/weixin_43768644/article/details/89501622

的方法建字典树方法会mle,因为需要4000*1001*字符种类 的空间

所以学习一下什么左儿子右兄弟的方法构造一下trie树。

具体请在代码中看。我觉的有点像链式前向星,son看做head数组,right看做next数组

举个例子,空trie树插入“black”

再插入“blank”

差不多就这样。

本题代码:(具体可能有些细节还没讲,相信你可以看懂!)

#include<cstdio>
#include<cstring>
#define ll long long

using namespace std;

const int N = 4000*1001 + 5;

struct node
{
    int son;
    int right;
    int sum;
    char ch;
}trie[N];
int id;
ll ans;

void init()
{
    ans = 0;
    id = 1;
    trie[0].right = 0;
    trie[0].son = 0;
    trie[0].sum = 0;
}

void insert(char *s)
{
    int u = 0,j;
    int len = strlen(s);
    for (int i=0;i<=len;i++){
        bool flag = false;

        for (j=trie[u].son;j!=0;j=trie[j].right){
            if (s[i]==trie[j].ch){
                flag = true;
                break;
            }
        }

        if (!flag){
            j = id++;
            trie[j].right = trie[u].son;
            trie[u].son = j;
            trie[j].ch = s[i];

            trie[j].son = 0;
            trie[j].sum = 0;
        }

        ans += (trie[u].sum+trie[j].sum);
        if (i==len) trie[j].sum++;

        trie[u].sum++;
        u = j;
    }
}

int main()
{
    int n;
    char in[1010];
    for (int kca=1;scanf("%d",&n),n;kca++){
        init();
        while (n--) scanf("%s",in),insert(in);
        printf("Case %d: %lld\n",kca,ans);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值