LeetCode 139. Word Break

问题描述

这里写图片描述

问题分析

  • 给定一个字符串和字符串集合,看能否将该字符串分割成字符集合里面的序列。
  • 一开始的想法就是类似于DFS 那种递归从i位置起枚举出所有分割情况,若字符集合存在该分割出的字符串,然后从新位置继续dfs,这样方面存在大量冗余计算,肯定是TLE的啦,然后改写动态规划。
  • dp[i] 表示从 i位置起分割出的全部子串能否都在字符串集合中。状态转移关系见具体实现。
  • 值得优化的两处:
    • 每一次分割出字符串,都要检查是否在字符串集合中,用 HashSet 的效率其实有点低, 倒不如将 字符串集合建立一个 Tire Tree。来检测有无
    • 先遍历,然后统计字符串集合中的最长串的长度,枚举分割的情况时,只要枚举到末尾或者 最长长度时即可停止。
  • 当然,还有另一种动态规划的思路,dp[i]表示 [0 ~ i]中分割的全部子串能否都在字符串集合中。 区别在于 i 是开头还是结尾罢了。

经验教训

  • 从dfs 到动态规划
  • 涉及到字符串集合时,想到利用 Tire Tree

代码实现

  • dfs(TLE)
    public boolean wordBreak(String s, List<String> wordDict) {
        HashSet<String> set = new HashSet<>();
        set.addAll(wordDict);
        char[] chs = s.toCharArray();
        return dfs(chs, 0, set);
    }

    public boolean dfs(char[] chs, int i, HashSet<String> set) {
        if (i == chs.length) {
            return true;
        }
        for (int end = i; end < chs.length; ++end) {
            String s = new String(chs, i, end - i + 1);
            if (set.contains(s) && dfs(chs, end + 1, set)) {
                return ture;
            }
        }
        return false;
    }
  • 动态规划
    public boolean wordBreak(String s, List<String> wordDict) {
        HashSet<String> set = new HashSet<>();
        set.addAll(wordDict);
        char[] chs = s.toCharArray();
        //dp[i] : i ~ chs.length - 1 可以由set中字符串构成
        boolean[] dp = new boolean[chs.length + 1];
        dp[chs.length] = true;
        for (int i = chs.length - 1; i >= 0; --i) {
            for (int end = i; end < chs.length; ++end) {
                String newStr = new String(chs, i, end - i + 1);
                if (set.contains(newStr) && dp[end + 1]) {
                    dp[i] = true;
                    break;
                }
            }
        }
        return dp[0];
    }
  • 动态规划(统计最大长度)
    public boolean wordBreak(String s, List<String> wordDict) {
        HashSet<String> set = new HashSet<>();
        int maxLength = 0;
        //统计字符串集合里面字符串的最大长度
        for (String str : wordDict) {
            maxLength = Math.max(maxLength, str.length());
            set.add(str);
        }
        char[] chs = s.toCharArray();
        //dp[i] : i ~ chs.length - 1 可以由set中字符串构成
        boolean[] dp = new boolean[chs.length + 1];
        dp[chs.length] = true;
        for (int i = chs.length - 1; i >= 0; --i) {
            for (int end = i; end < chs.length && end - i + 1 <= maxLength; ++end) { //不超过maxLength
                String newStr = new String(chs, i, end - i + 1);
                if (set.contains(newStr) && dp[end + 1]) {
                    dp[i] = true;
                    break;
                }
            }
        }
        return dp[0];
    }

猜你喜欢

转载自blog.csdn.net/zjxxyz123/article/details/80214523