Word Break

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".

第一种思路:

使用递归方法

public class Solution {
    public boolean wordBreak(String s, Set<String> dict) {
        Iterator<String> iterator = dict.iterator();
        while(iterator.hasNext()){
                String tmp = iterator.next();
                if(s.indexOf(tmp) > -1){//s中存在tmp,可以分割
                    String[] sub = s.split(tmp);
                    int count = 0;
                    for(int i = 0; i < sub.length; i ++){
                        if(wordBreak(sub[i],dict)){
                            count++;
                        }
                    }
                    if(count == sub.length){
                        return true;
                    }
                }
        }
        return false;
    }
}

Time Limit Exceeded

分析可知,递归很耗费时间!

public class Solution {
    public boolean wordBreak(String s, Set<String> dict) {
        int len = s.length();
        int[][] dp = new int[len][len];
        for(int i = 0 ; i < len ; i ++){
            for(int j = i ; j < len ; j ++){
                String tmp = s.substring(i,j+1);
                if(dict.contains(tmp)){
                    dp[i][j] = 1;//(i~j)是一个字典项
                }
            }
        }
        return path(dp,0);
    }
    private boolean path(int[][] dp ,int index){
        if(index >= dp[0].length){
            return true;
        }
        boolean flag = false;
        for(int i = index ; i < dp[0].length; i ++){
            if(dp[index][i] == 1){
                if(path(dp,i+1)){
                    return true;
                }
            }
        }
        return false;
    }
}

思想是先寻找(i,j)是否在字典里,这样可以使用O(n2)的时间创建一副“地图“出来

然后再从地图中找到一条路使得(0,n)无重复节点。

Time Limit Exceeded

string=“aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab“

dict:["a","aa","aaa","aaaa","aaaaa","aaaaaa","aaaaaaa","aaaaaaaa","aaaaaaaaa","aaaaaaaaaa"]

dp[152*152] =

1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0

   1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0

      1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0

         1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0

............

我们发现要递归10*152+才能发现不可分割,

而实际上我们如果注意到了“b“,那么就可以很快的确定不可分割,因为“b“在字典里没有出现

public class Solution {
    public boolean wordBreak(String s, Set<String> dict) {
        //验证是否s里存在dict不存在的字符
                int[] c = new int[26];
                for(int i = 0; i < s.length(); i ++){
                        c[s.charAt(i)-'a'] = 1;
                }
                //for(int i = 0 ; i < 26 ; i ++){
                //      System.out.println((char)(i+'a')+":" + (int)c[i]);
                //}
                for(int i = 0; i < 26 ; i ++){
                        if(c[i] == 1){
                                int count = 0;
                                Iterator<String> ite = dict.iterator();
                                while(ite.hasNext()){
                                        if(ite.next().indexOf((char)(i+'a')) < 0){
                                                count++;
                                        }
                                }
                                if(count == dict.size()){
                                        System.out.println("here");
                                        return false;
                                }

                        }
                }
                //只有一个字符
                if(s.length() == 1){
                        return true;
                }
        
        int len = s.length();
        int[][] dp = new int[len][len];
        for(int i = 0 ; i < len ; i ++){
            for(int j = i ; j < len ; j ++){
                String tmp = s.substring(i,j+1);
                if(dict.contains(tmp)){
                    dp[i][j] = 1;//(i~j)是一个字典项
                }
            }
        }
        return path(dp,0);
    }
    private boolean path(int[][] dp ,int index){
        if(index >= dp[0].length){
            return true;
        }
        boolean flag = false;
        for(int i = index ; i < dp[0].length; i ++){
            if(dp[index][i] == 1){
                if(path(dp,i+1)){
                    return true;
                }
            }
        }
        return false;
    }
}

string="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab", dict:["a","aa","ba"]

Time Limit Exceeded

看来只能另辟蹊径了。

原文  http://blog.csdn.net/ljphhj/article/details/21643391

核心思想是F(0,n)= F(0,i-1)+ F(i,j-1)+F(j,n)

public class Solution {
    public boolean wordBreak(String s, Set<String> dict) {
        boolean flag = false;
       List<Integer> list = new ArrayList<Integer>();//存储所有可能的从i到n的情况
       int len = s.length();
       for(int i = len - 1 ; i >= 0 ; i --){
           String tmp = s.substring(i);
           if(dict.contains(tmp)){//i~n是一个字典项
               list.add(i);
           }else{//i~n不是一个字典项,那么查找是否存在j,使得F(i,n)=F(i,j)+ F(j+1,n)
               for(Integer n : list){
                   if(dict.contains(s.substring(i,n))){//实际查询F(i,n-1)是否存在,所以不能是substring(i,n+1)
                       list.add(i);
                       break;
                   }
               }
           }
       }
       if(list.size()==0){
          flag = false; 
       }else{
           if(list.get(list.size()-1) == 0){
               flag = true;
           }else{
               flag = false;
           }
       }
       return flag;
    }
}

string = "leetcode"

dict=["leet","co","de","code"]

通过上述程序,list存着什么?

list=[6,4,0]

string = "leetcode"

dict=["leet","de","code"]

通过上述程序,list存着什么?

list=[6,4,0]

思考可知:这两处的4是不同含义

第一个4指的是{4,6},而第二个4是{4,n}

也就是说上述程序的list只是找到从i到n可以使用dict分割,至于如何分割,还得分析。

public class Solution {
    public boolean wordBreak(String s, Set<String> dict) {
        int len = s.length();
        boolean[] arrays = new boolean[len+1];
        arrays[0] = true;
        for (int i = 1; i <= len; ++i){
            for (int j = 0; j < i; ++j){
                if (arrays[j] && dict.contains(s.substring(j, i))){
                // f(n) = f(0,i) + f(i,j) + f(j,n)
                arrays[i] = true; //到i是可分割的
                break;
                }
            }
        }
        return arrays[len];
    }
}

分析上述两个程序可知,思想是一致的,只不过是一个从前往后思考,一个是从后往前思考。

 

posted on 2015-03-30 11:31  琼华  阅读(119)  评论(0编辑  收藏  举报

导航