LeetCode 140 (LintCode 582) Word Break II

记忆化搜索分解字符串思路及复杂度

思路

记忆化搜索(使用记忆化的原因是有的分解形式会被重复用到),基本还是分治的思路。使用一个hashmap叫做memo来记录已经分解过的字符串及其分解形式,这样如果遇到一个新的字符串恰好在memo中,就直接返回结果而不用再搜索一遍了。
搜索过程:首先将输入字符串依次按照下标分解成两个字串s1和s2,然后检查s1是否在字典里,如果在的话就将s2交给一个“总监”,得到结果s2_res。然后将s1和该结果中的每一个可能字串进行组合(用空格隔开),加入到答案res中。最后更新memo和返回res。
【注意:需要对memo进行初始化,使用空字符串进行初始化,目的是为了防止搜索函数返回一个空list(长度=0)而不是空字符串,导致其中的判断条件出错(if(item==””)那里)】

复杂度

时间复杂度O(n∗2n)O(n*2^n)O(n2n): n为字符串长度
空间复杂度O(n∗len(dict))O(n*len(dict))O(nlen(dict))

代码

实现1

public class Solution {
    /*
     * @param s: A string
     * @param wordDict: A set of words.
     * @return: All possible sentences.
     */
    public List<String> wordBreak(String s, Set<String> wordDict) {
        // write your code here
        
        Map<String, List<String>> memo = new HashMap<>();
        // 正确初始化,否则会导致下面的dfs返回空list而不是空字符串
        memo.put("", new ArrayList<>());
        memo.get("").add("");
        
        return dfs(s, wordDict, memo);
    }
    
    public List<String> dfs(String s, Set<String> wordDict, Map<String, List<String>> memo) {
        
        if(memo.containsKey(s)) {
            return memo.get(s);
        }
        
        List<String> res = new ArrayList<>();
        
        for(int i = 1; i <= s.length(); i++) {
            String s1 = s.substring(0, i);
            String s2 = s.substring(i);
            
            if(wordDict.contains(s1)) {
                // s2 的分解形式
                List<String> s2_res = dfs(s2, wordDict, memo);
                
                for(String str : s2_res) {
                    if(str == "") {
                        res.add(s1);
                    } else {
                        res.add(s1 + " " + str);
                    }
                }
            }
        }
        
        // 在这里统一更新memo,而不是得到s2_res后就更新
        memo.put(s, res);
        return res;
    }
}

实现2

class Solution {
    public List<String> wordBreak(String s, List<String> wordDict) {
        Map<String, List<String>> memo = new HashMap<>();
        return helper(s, wordDict, memo);
    }
    
    private List<String> helper(String s, List<String> wordDict,
                                Map<String, List<String>> memo) {
        if (memo.containsKey(s)) {
            return memo.get(s);
        }
        
        List<String> result = new ArrayList<>();
        
        // in case the input is "" (initial input)
        if (s.length() == 0) {
            return result;
        }
        
        //判断整个字符串是否在dict中,因为下面的for循环中如果整个字符串都在字典中,会得到空串,所以在这里判断
        if (wordDict.contains(s)) {
            result.add(s);
        }
        
        //保证切割两侧至少都有1个元素
        //因为如果一侧为空串的话,result为空(主要是考虑整个串都匹配的问题)
        for (int i = 1; i < s.length(); i++) {
            String prefix = s.substring(0, i);
            if (!wordDict.contains(prefix)) {
                continue;
            }
            
            String suffix = s.substring(i);
            List<String> segs = helper(suffix, wordDict, memo);
            for (String seg : segs) {
                result.add(prefix + " " + seg);
            }
        }
        
        memo.put(s, result);
        return result;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值