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:
- The number of elements of the given array will not exceed
10,000
- The length sum of elements in the given array will not exceed
600,000
. - All the input string will only include lower case letters.
- 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里面。