115、完全背包-LeetCode-139.单词拆分

题目:

给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。

注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。

来源:力扣(LeetCode)

思路:

优化:因为进行判断时,不用从头开始,效率会很差!

可以记录字典中最长字串的长度,从后往前找,当要匹配的子串长度已经大于最长子串的长度了,肯定就不会成功,结束即可!

1)一个重要的点:对字典是否包含某段,自己的第一想法是 不好判断,要组新的字符串;

但是最方便的解法是:使用substring()方法,使用下标获取字串,然后进行判断

2)对于背包容量在外,物品在内的理解:

如果物品在外,按照之前的背包问题!字典中的字串每次循环,只加进来一个

之前的思路是:如果只有该元素之前的元素,判断怎么组成最后的结果,要的是结果数;

这次只判断是否可以,就一个结果,是与否!

物品在内,每次判断字串时,就将字典中的所有结果拿来进行比较;更容易得到是或者否的结果

其实最后都是一样的循环,感觉时间复杂度并不会有很高的提升!

总的来说,感觉思路固定,不是很难!

代码:

3)进一步优化 : 时间复杂度为O(N * M)

一样的判定条件:

        for(int i = 1;i <= n;i++){
            for(int j = Math.max(i - maxLength,0);j < i;j++ )
class Solution {
    public boolean wordBreak(String s, List wordDict) {
        //List默认没有存重复的字符串,contains就可以判断,和集合Set是一样的
        int n = s.length();
        int maxLength = 0;//记录字典中字符串最大长度!
        boolean dp[] = new boolean[n + 1];//dp数组代表的是,到该下标处(+1)处的字符串是否可以拼接
        Set wordDictSet = new HashSet(wordDict);

        //优化:因为不需要每次都从最开始的位置进行判断:可以优化
        for(String str : wordDict){
            maxLength = Math.max(maxLength,str.length());
        }

        dp[0] = true;//初始化
        for(int i = 1;i <= n;i++){//背包容量,可以取到n,因为子串获取是左闭右开
            for(int j = i;j >= 0 && j >= i - maxLength;j-- ){//对字典里的子串进行比较

                //感觉这里可以优化:contains附带了一个O(N)的时间复杂度
                if(dp[j] == true && wordDictSet.contains(s.substring(j,i))){
                    //之前有包括的子串,且后面的位置,也被包括,就赋值为true
                    dp[i] = true;
                    //赋值为true,就可以跳出
                    break;
                }
            }
        }
        return dp[n];
    }
}

1)完全背包 + 背包容量在外,物品在内:O(N三次方),因为List查找是O(N)的

class Solution {
    public boolean wordBreak(String s, List wordDict) {
        //List默认没有存重复的字符串,contains就可以判断,和集合Set是一样的
        int n = s.length();
        boolean dp[] = new boolean[n + 1];//dp数组代表的是,到该下标处(+1)处的字符串是否可以拼接
        dp[0] = true;//初始化
        for(int i = 1;i <= n;i++){//背包容量,可以取到n,因为子串获取是左闭右开
            for(int j = 0;j <= i;j++ ){//对字典里的子串进行比较

                //感觉这里可以优化:contains附带了一个O(N)的时间复杂度
                if(dp[j] == true && wordDict.contains(s.substring(j,i))){
                    //之前有包括的子串,且后面的位置,也被包括,就赋值为true
                    dp[i] = true;
                    //赋值为true,就可以跳出
                    break;
                }
            }
        }
        return dp[n];
    }
}

2)使用Set优化复杂度,因为Set查找是 O(1)

class Solution {
    public boolean wordBreak(String s, List wordDict) {
        //List默认没有存重复的字符串,contains就可以判断,和集合Set是一样的
        int n = s.length();
        boolean dp[] = new boolean[n + 1];//dp数组代表的是,到该下标处(+1)处的字符串是否可以拼接
        Set wordDictSet = new HashSet(wordDict);

        dp[0] = true;//初始化
        for(int i = 1;i <= n;i++){//背包容量,可以取到n,因为子串获取是左闭右开
            for(int j = 0;j <= i;j++ ){//对字典里的子串进行比较

                //感觉这里可以优化:contains附带了一个O(N)的时间复杂度
                if(dp[j] == true && wordDictSet.contains(s.substring(j,i))){
                    //之前有包括的子串,且后面的位置,也被包括,就赋值为true
                    dp[i] = true;
                    //赋值为true,就可以跳出
                    break;
                }
            }
        }
        return dp[n];
    }
}

你可能感兴趣的:(动态规划,leetcode,动态规划,算法)