472. Concatenated Words

Given a list of words (without duplicates), please write a program that returns all concatenated words in the given list of words.

A concatenated word is defined as a string that is comprised entirely of at least two shorter words in the given array.

Example:

Input: ["cat","cats","catsdogcats","dog","dogcatsdog","hippopotamuses","rat","ratcatdogcat"]

Output: ["catsdogcats","dogcatsdog","ratcatdogcat"]

Explanation: "catsdogcats" can be concatenated by "cats", "dog" and "cats"; 
"dogcatsdog" can be concatenated by "dog", "cats" and "dog";
"ratcatdogcat" can be concatenated by "rat", "cat", "dog" and "cat".

Note:

  1. The number of elements of the given array will not exceed 10,000
  2. The length sum of elements in the given array will not exceed 600,000.
  3. All the input string will only include lower case letters.
  4. The returned elements order does not matter.
class Solution {
    private static Node root;
    
    public List<String> findAllConcatenatedWordsInADict(String[] words) {
        if (words == null || words.length == 0)
            return new ArrayList<>();
        
        root = new Node();
        buildTrie(words);
        
        List<String> result = new LinkedList<>();
        for (String word : words) {
            if (isConcatenated(word, 0, 0))
                result.add(word);
        }
        return result;
    }
    
    // Return true if word starting from index is concatenated
    boolean isConcatenated(String word, int index, int countConcatenatedWords) {
        if (index == word.length())
            return countConcatenatedWords >= 2;
        
        Node ptr = root;
        for (int i = index; i < word.length(); i++) {
            if (ptr.children[word.charAt(i) - 'a'] == null) 
                return false;
            ptr = ptr.children[word.charAt(i) - 'a'];
            
            if (ptr.isWordEnd)
                if (isConcatenated(word, i + 1, countConcatenatedWords + 1))
                    return true;
        }
        
        return false;
    }
    
    private void buildTrie(String[] words) {
        Node ptr;
        for (String word : words) {
            ptr = root;
            for (char ch : word.toCharArray()) {
                int order = ch - 'a';
                if (ptr.children[order] == null) {
                    ptr.children[order] = new Node();
                } 
                ptr = ptr.children[order];
            }
            ptr.isWordEnd = true;
        }
    }
    
    class Node {
        Node[] children;
        boolean isWordEnd;
        
        public Node() {
            children = new Node[26];
            isWordEnd = false;
        }
    }
}

Trie!!!屌!@!!https://leetcode.com/problems/concatenated-words/discuss/176805/Trie-with-Explanations

膜拜,首先把words存成trie,然后递归调用函数来检查是否当前word可以被concat成两个或以上,

class Solution {
    public List<String> findAllConcatenatedWordsInADict(String[] words) {
        Set<String> prev = new HashSet();
        List<String> res = new ArrayList();
        if(words.length == 0 || words == null) return res;
        Arrays.sort(words, (a, b) -> a.length() - b.length());
        
        for(String word: words) {
            if(help(word, prev)) res.add(word);
            prev.add(word);
        }
        return res;
    }
    
    public boolean help(String word, Set<String> prev) {
        if(prev.isEmpty()) return false;
        int n = word.length();
        boolean dp[] = new boolean[n + 1];
        dp[0] = true;
        
        for(int i = 1; i <= n; i++) {
            for(int j = 0; j < i; j++) {
                if(dp[j] && prev.contains(word.substring(j, i))) {
                     dp[i] = true;
                    break;
                }
            }
        }
        return dp[n];
    }
}

阳间方法,类似word break,先把string 按长短排列,然后每个string判断能不能由后面的concat成,能就加到res里面。

原文地址:https://www.cnblogs.com/wentiliangkaihua/p/13396221.html