Leetcode 之 Word Break1 和 Word Break2

Word Beark1
Given a string s and a dictionary of words dict, determine if s can be segmented into a space-separated sequence of one or more dictionary words.

For example, given
s = “leetcode”,
dict = [“leet”, “code”].

Return true because “leetcode” can be segmented as “leet code”.
和Word Break2
Given a string s and a dictionary of words dict, add spaces in s to construct a sentence where each word is a valid dictionary word.

Return all such possible sentences.

For example, given
s = “catsanddog”,
dict = [“cat”, “cats”, “and”, “sand”, “dog”].

A solution is [“cats and dog”, “cat sand dog”].

I 主要是判断字典中的单词能否组成句子,只要找到一组解就可以break,开始用递归,直接TLE,后来借鉴网上的方法用DP ,递推关系是f(n) = f(0,i) + f(i,j) + f(j,n),也就是遍历一遍整个句子,用两个下标来指示,跟字典比较来判断下标间能够构成一个单词。在遍历过程中,维护一个标记数组,记录在句子每一位时,它前面的部分是否能够构成部分句子。这样,我们只需要判断数组中句子的末尾的标记就可以。

public boolean wordBreak3(String s, Set<String> wordDict) {
        boolean[] arrays = new boolean[s.length() + 1];
        arrays[0] = true;
        for(int i = 1;i <= s.length();i++){         
            for(int j = 0;j < i;j++){
                if(arrays[j] && wordDict.contains(s.subSequence(j, i))){
                    arrays[i] = true;
                    break;
                }
            }
        }
        return arrays[s.length()];
    }

26 / 26 test cases passed.
Status: Accepted
Runtime: 252 ms

后来做II,与I的不同在于它不仅要判断能否找到,还要把所有可能的组合都列出来。开始想在找单词的同时生成组合,就用递归的方法:

把句子分成两部分,已经找到的剩下要找的子串。遍历整个字典,判断包含句子首位的单词是否在字典中有,如果没有的话可以直接返回了,如果有的话,在剩下要找的子串中中去掉这个单词,把这部分放到已经找到的部分,然后再递归。直到已经剩下要找的子串为空,说明全部找到,返回结果。

这里有几个需要注意的部分:
1、一定要与剩下要找的子串的首位进行比较。
2、在判断时,加入I时生成的标记数组进行判断进行剪枝,只有当这一位之前的部分能够构成句子,才需要进行下一步递归。
3、在递归前,先对字典中的单词进行了一遍筛选,如果单词在句子中没有,就直接在字典中删掉了,这样能够减少遍历字典的时间。

交上去,还是TLE,死在了字典里全是a,要找‘aaaaaaaa…ab’这个句子上,借鉴网上的做法,先用DP生成的标记数组来判断需不需要分割,如果字典不能组成句子的话就没必要进入递归了,加上这一步,AC了。

上一个java版本的代码:


    public List<String> result = new ArrayList<String>();
    boolean[] arrays;

    public List<String> wordBreak(String s, Set<String> wordDict) {
        ArrayList<String> dic = new ArrayList<String>();
        Iterator<String> iter = wordDict.iterator();
        while(iter.hasNext()){
            String word = iter.next();
            if(s.indexOf(word) != -1){
                dic.add(word);
            }
        }

        arrays = new boolean[s.length() + 1];
        arrays[0] = true;
        for(int i = 1;i <= s.length();i++){         
            for(int j = 0;j < i;j++){
                if(arrays[j] && wordDict.contains(s.subSequence(j, i))){
                    arrays[i] = true;
                    break;
                }
            }
        }
        if(arrays[s.length()] == true)  find("","", s, dic);
        return result;
    }

    /**
     * 分割句子
     * @param match 当前已匹配的子串(带空格)
     * @param str 当前已匹配的子串(不带空格)
     * @param string 剩余需要匹配的子串
     * @param dic 字典
     */
    public void find(String match, String str, String string , ArrayList<String> dic){

        if("".equals(string)){
            result.add(match);
            return;
        }

        for(String word:dic){

            if(string.indexOf(word) == 0 && arrays[str.length()]){
                String temp = match;
                if("".equals(temp))
                    temp = word; 
                else
                    temp += " "+word;
                find(temp,str + word, string.substring(word.length()),dic);
            }
        }
    }

29 / 29 test cases passed.
    Status: Accepted
Runtime: 296 ms
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值