每日写题分享–单词拆分/动态规划/剪枝

题目描述:

给你一个字符串 s 和一个字符串列表 wordDict 作为字典,判定 s 是否可以由空格拆分为一个或多个在字典中出现的单词。

说明:拆分时可以重复使用字典中的单词。

题目链接戳此

思路:首先将字典放进set里面,方便判断字典中是否包含某个单词,并求出字典中最长单词的长度(下面解析中有解释)。再根据题意,如果一个字符串合法(即拆分后的单词全都在字典里能查询到),那么这个字符串去掉一个单词也是合法的,由此能得到动态转移方程。

具体实现根据下面代码解析:如果在单词长度为 i 时,j 从 i - 1开始向前探索,一直探索到0位置时,如果满足 s的(i - j)不分的字符串存在于字符串,并且dp[0]为true,就说明这一段存在于字典里,这是定义dp[i] = true,假设此时的i位置为k。下一次探索的时候j从新的i-1位置开始,此时就不用探索到0位置才能返回true了,因为只要j从i位置开始走,到k的位置,满足[k,j]这一段存在字典中就可以了,if条件里dp[k]在上一次已经被置为true了,符合条件语句的判断。

刚才描述的代码还是可以优化的,也就是j 从 i - 1开始向前探索,一直探索到0位置,如果中间发现i-j大于字典中出现的单词中最大的长度,那么字典就不可能包含这个单词,所以可以在if语句多加上这个条件。这也就是剪枝思想。

代码实现如下:

class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        int len = s.length();
        int max = 0;
        Set<String> set = new HashSet<>();
        for (String str : wordDict) {
            if (!set.contains(str)) {
                set.add(str);
                max = Math.max(max,str.length());
            }
        }        
        boolean[] dp = new boolean[len + 1];

        //dp[0]本身没有意义,题目中给的s是非空的,这里只是方便解题给定的初始值。
        dp[0] = true;
        for (int i = 1; i <= s.length();i++) {

        //i - j <= max作用:剪枝。如果探索的长度大于字典里最长单词的长度,就没必要继续探索了。
            for (int j = i - 1;j >= 0 && i - j <= max ;j--) {
                if (dp[j] && set.contains(s.substring(j,i))) {
                    dp[i] = true;
                    break;
                }
            }
        }
        return dp[len];
    }
}

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>