LeetCode 472 连接词
给你一个 不含重复 单词的字符串数组 words
,请你找出并返回 words
中的所有 连接词 。
连接词 定义为:一个完全由给定数组中的至少两个较短单词组成的字符串。
示例 1:
输入:words = ["cat","cats","catsdogcats","dog","dogcatsdog","hippopotamuses","rat","ratcatdogcat"] 输出:["catsdogcats","dogcatsdog","ratcatdogcat"] 解释:"catsdogcats" 由 "cats", "dog" 和 "cats" 组成; "dogcatsdog" 由 "dog", "cats" 和 "dog" 组成; "ratcatdogcat" 由 "rat", "cat", "dog" 和 "cat" 组成。
示例 2:
输入:words = ["cat","dog","catdog"] 输出:["catdog"]
提示:
1 <= words.length <= 104
0 <= words[i].length <= 1000
words[i]
仅由小写字母组成0 <= sum(words[i].length) <= 105
动态规划 + 字符串哈希
// 保存字符串转换得到的哈希值
static Set<Long> set = new HashSet<>();
// 目的是转换成唯一的一个数字,131 是个不错的进制
static int P = 131, OFFSET = 128;
/**
* DP + 字符串哈希(将一个字符串转换成一个唯一的数字)
*
* @param words
* @return
*/
public static List<String> findAllConcatenatedWordsInADict(String[] words) {
if (words == null || words.length == 0) return new ArrayList<>();
set.clear();
// 字符串哈希
for (String word : words) {
long hash = 0;
for (char ch : word.toCharArray()) {
hash = hash * P + (ch - 'a') + OFFSET;
}
set.add(hash);
}
List<String> ans = new ArrayList<>();
for (String word : words) {
if (check(word)) {
ans.add(word);
}
}
return ans;
}
/**
* DP 判断字符串S是否为连接词
*
* @param s
* @return
*/
private static boolean check(String s) {
if (s == null) return false;
int n = s.length();
// dp[i] 表示字符串s的前i个字符,能够切分的最大item数的个数
int[] dp = new int[n + 1];
Arrays.fill(dp, -1);
// 初始状态
dp[0] = 0;
//从dp[i]出发,枚举范围[i+1,n],找到可由dp[i]所能更新的状态dp[j],并尝试使用dp[i]来更新dp[j]
for (int i = 0; i <= n; i++) {
if (dp[i] == -1) continue;
long cur = 0;
for (int j = i + 1; j <= n; j++) {
cur = cur * P + (s.charAt(j - 1) - 'a') + OFFSET;
// 状态转换,如果Set集合中包含由s[i~j]的字符串构成的哈希值,更新状态
if (set.contains(cur)) dp[j] = Math.max(dp[j], dp[i] + 1);
}
if (dp[n] > 1) return true;
}
return false;
}
测试用例
public static void main(String[] args) {
String[] words = new String[]{"cat", "cats", "catsdogcats", "dog", "dogcatsdog", "hippopotamuses", "rat", "ratcatdogcat"};
List<String> strings = FindAllConcatenatedWordsInADict.findAllConcatenatedWordsInADict(words);
System.out.print("FindAllConcatenatedWordsInADict demo01 result : [");
for (String str : strings) {
System.out.print("," + str);
}
System.out.println("]");
words = new String[]{"cat", "dog", "catdog"};
strings = FindAllConcatenatedWordsInADict.findAllConcatenatedWordsInADict(words);
System.out.print("FindAllConcatenatedWordsInADict demo02 result : [");
for (String str : strings) {
System.out.print("," + str);
}
System.out.println("]");
}
测试结果
FindAllConcatenatedWordsInADict demo01 result : [,catsdogcats,dogcatsdog,ratcatdogcat]
FindAllConcatenatedWordsInADict demo02 result : [,catdog]