力扣 745. 前缀和后缀搜索

题目来源:https://leetcode.cn/problems/prefix-and-suffix-search/

大致题意:
设计一个类,初始化时给定一个字符串数组作为字典,该类包含一个方法:

  • f(string pref, string suff) 返回词典中具有前缀 prefix 和后缀 suff 的单词的下标。如果存在不止一个满足要求的下标,返回其中 最大的下标 。如果不存在这样的单词,返回 -1 。

思路

  1. 使用前缀树存下所有前缀和对应的索引,以及字典原字符串倒置后的前缀树,这里称其为后缀树
  2. 对于方法 f(string pref, string suff),判断前缀树中是否存在 pref,若存在取出该前缀对应的索引集合,同理,取出后缀树的索引集合
  3. 若其中索引集合有一个为空,那么显然字典中不存在该单词,返回 -1 即可;否则,在两个索引集合中查找单词索引,若找到则返回最大的(这里使用双指针倒序遍历集合,第一个找到的就是最大的),若未找到则返回 -1

代码:

public class WordFilter {
    
    Trie preRoot;   // 前缀树根节点
    Trie sufRoot;   // 后缀树根节点

    public WordFilter(String[] words) {
        preRoot = new Trie();
        sufRoot = new Trie();
        StringBuffer sb;
        // 将给定字典中所有单词插入前缀树和后缀树中
        for (int i = 0; i < words.length; i++) {
            sb = new StringBuffer();
            insert(preRoot, words[i], i);
            sb.append(words[i]);
            insert(sufRoot, sb.reverse().toString(), i);
        }
    }

    /**
     * 判断字典中是否存在前缀为 pref,后缀为 suff 的单词
     * @param pref
     * @param suff
     * @return
     */
    public int f(String pref, String suff) {
        List<Integer> preList = search(preRoot, pref);
        StringBuffer sb = new StringBuffer();
        sb.append(suff).reverse();
        List<Integer> sufList = search(sufRoot, sb.toString());
        // 若有一个索引集合为空,则不存在该单词
        if (preList == null || sufList == null) {
            return -1;
        }
        int idx1 = preList.size() - 1;
        int idx2 = sufList.size() - 1;
        // 双指针倒序遍历
        while (idx1 >= 0 && idx2 >= 0) {
            int preListIdx = preList.get(idx1);
            int sufListIdx = sufList.get(idx2);
            // 找到,直接返回
            if (preListIdx == sufListIdx) {
                return preListIdx;
            } else if (preListIdx > sufListIdx) {
                idx1--;
            } else {
                idx2--;
            }
        }
        // 未找到,返回 -1
        return -1;
    }

    /**
     * 讲单词插入给定前缀树中
     * @param root
     * @param word
     * @param index
     */
    public void insert(Trie root, String word, int index) {
        Trie trie = root;
        for (int i = 0; i < word.length(); i++) {
            int idx = word.charAt(i) - 'a';
            if (trie.children[idx] == null) {
                trie.children[idx] = new Trie();
            }
            trie = trie.children[idx];
            // 插入索引
            trie.indexList.add(index);
        }
    }

    /**
     * 在给定前缀树中搜索给定前缀,并返回索引集合
     * @param root
     * @param prefix
     * @return
     */
    public List<Integer> search(Trie root, String prefix) {
        Trie trie = root;
        for (int i = 0; i < prefix.length(); i++) {
            int idx = prefix.charAt(i) - 'a';
            if (trie.children[idx] == null) {
                return null;
            }
            trie = trie.children[idx];
        }
        return trie.indexList;
    }

    // 前缀树类
    class Trie {
        Trie[] children;
        List<Integer> indexList;    // 用来存含有当前前缀的字符串索引集合

        public Trie() {
            children = new Trie[26];
            indexList = new ArrayList<>();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三更鬼

谢谢老板!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值