【leetCode】 140-单词拆分

219 阅读1分钟

这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战

链接

leetcode-cn.com/problems/wo…

前置知识

  • 字典树
    • 字典树是以相同前缀为根节点设置的树,方便于检索,具体的实现见下面的代码。
    • 在各种可以以相同前缀入手的问题中,字典树是一个可参考的方式,因为字符串长度不定,因此无论是用二进制来保存还是hash值,都不太好解决。

题解

分解为3个问题:

  • 根据字典,构造字典树
  • 根据字典树,构造dp数组,含义为:s为字符串,dp[i] [j] = (s[i] ~ s[j])是否在字典中能找到,如果有的话则为字典中的字符,否则则为-1
  • 根据dp数组,求出整个字符串可由字典构成的所有可能

根据这个指导思想,三步走就得到如下代码:

static class Trie{

    boolean root;

    boolean word;

    int wordIdx;

    Trie[] leaves;

    public Trie(boolean root) {
        this.root = root;
        leaves = new Trie[26];
        wordIdx = -1;
    }

    public Trie gets(char c){
        return leaves[c - 'a'];
    }

    public static Trie buildTrie(List<String> wordDict){
        Trie root = new Trie(true);
        for (int i1 = 0; i1 < wordDict.size(); i1++) {
            String s = wordDict.get(i1);
            Trie cur = root;
            for (int i = 0; i < s.length(); i++) {
                Trie level = cur.leaves[s.charAt(i) - 'a'];
                if (level == null) {
                    level = new Trie(false);
                    cur.leaves[s.charAt(i) - 'a'] = level;
                }
                if (i == s.length() - 1) {
                    level.word = true;
                    level.wordIdx = i1;
                }
                cur = level;
            }
        }
        return root;
    }
}


public List<String> wordBreak(String s, List<String> wordDict) {
    Trie root = Trie.buildTrie(wordDict);
    List<String> res = new ArrayList<>();
    int[][] dp = new int[s.length()][s.length()];
    for (int i = 0; i < dp.length; i++) Arrays.fill(dp[i], -1);
    updateDP(dp,s,0,root);
    buildString(dp,res,wordDict,0,"");
    return res;
}

public void updateDP(int[][] dp,String s,int start,Trie dic){
    Trie cur = dic;
    for(int j = start;j<s.length();j++){
        Trie nxt = cur.gets(s.charAt(j));
        if(nxt == null) break;
        if(nxt.word){
            dp[start][j] = nxt.wordIdx;
            updateDP(dp,s,j+1,dic);
        }
        cur = nxt;
    }
}

public void buildString(int[][] dp,List<String> res,List<String> dict,int curIdx,String startString){
    if(curIdx==dp.length){
        res.add(startString);
        return;
    }
    if(curIdx!=0) startString += " ";
    int[] ints = dp[curIdx];
    for (int i1 = curIdx, intsLength = ints.length; i1 < intsLength; i1++) {
        int dictIdx = dp[curIdx][i1];
        if (dictIdx == -1) continue;
        buildString(dp,res,dict,i1+1,startString+dict.get(dictIdx));
    }
}

执行用时:1 ms, 在所有 Java 提交中击败了95.66%的用户

内存消耗:36.6 MB, 在所有 Java 提交中击败了63.25%的用户