题解/算法 {3093. 最长公共后缀查询}

题解/算法 {3093. 最长公共后缀查询}

@LINK: https://leetcode.cn/problems/longest-common-suffix-queries/;

看一个超内存的做法:
S中的所有字符串的所有后缀, 都放到一个map< string, pair<int,int> >里面 (pair记录{字符串最短长度, 字符串下标}); 然后查询时 也是遍历当前要查询的字符串的所有后缀 去map里面查询;
一共有多少个后缀呢? 注意不是1e4 * 5e3, 因为题目说了*wordsContainer[i].length 的和至多为 5 * 1e5, 也就是 一共最多是5e5个后缀, 可是 再加上每个后缀的长度*, 他是5e5 * 5e5级别, 会爆空间的;

看一个正确的做法(但不是最优解):
既然爆空间了, 那对字符串进行哈希 变成一个整数, 都放到map< int, pair<int,int> >里面, 此时就不会爆空间了;
但会发生哈希冲突, 因为字符串太多了, 因此 需要用大哈希(即将1e9+7 改为1e18+7);

vector<int> stringIndices(vector<string>& S, vector<string>& Q) {
    ___HashString::___Calc_SubStringsHash Calc;

    unordered_map< ___HashString::__HashModularType_::__UnsignedModType_, pair<int,int> > MP;
    FOR_( i, 0, S.size()-1){
        int len = S[i].size();

        if( (MP.find(0)==MP.end()) || (len<MP[0].first)){ MP[0] = {len, i};} // 空字符串;

        Calc.Initialize( S[i].data(), len);
        FOR_( t, 1, len){
            auto cur = Calc.Get_hash_subString( t-1, len-1).Value;

            if( (MP.find(cur)==MP.end()) || (len<MP[cur].first)){ MP[ cur] = {len, i};}
        }
    }

    vector<int> ANS( Q.size(), -1);
    FOR_( q, 0, ANS.size()-1){
        int len = Q[q].size();

        Calc.Initialize( Q[q].data(), len);
        FOR_( t, 1, len){
            auto cur = Calc.Get_hash_subString( t-1, len-1).Value;
            if( MP.find( cur) != MP.end()){ ANS[q] = MP[cur].second; break;}
        }

        if( ANS[q] == -1){
            ANS[q] = MP[0].second; // 空字符串
        }
    }
    return ANS;
}

最优解: 字典树Trie;
将S中所有字符串 逆序的 放到Trie里面, 然后每个节点记录pair<int,int>信息;
查询时 也是将要查询的字符串 逆序处理后, 放到Trie里查询;

vector<int> stringIndices(vector<string>& S, vector<string>& Q){
    static ___TrieTree Tr;
    Tr.Initialize();

    FOR_( i, 0, S.size()-1){
        auto & s = S[i];
        std::reverse( s.begin(), s.end());
        Tr.Insert( s.data(), s.size(), {s.size(), i});
    }

    vector<int> ANS(Q.size());
    FOR_( i, 0, Q.size()-1){
        auto & s = Q[i];
        std::reverse( s.begin(), s.end());
        ANS[i] = Tr.Query( s.data(), s.size());
    }
    return ANS;
}
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值