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]
posted @ 2021-12-28 19:49  枫叶艾辰  阅读(45)  评论(0编辑  收藏  举报