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];

    }

}

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

 

你可能感兴趣的:(break)