Word break I
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”.
这个题目再dp层面和palindrome partition一模一样,一维就够了。但是对于长字符串会超时,这个时候就需要用dict建立prefix tree来剪枝,当前substring已经不是一个valid prefix时,就可以停止往后判断。
其实c++的题目完全不需要优化就过了呵呵呵。。。
[code]
public class Solution {
public boolean wordBreak(String s, Set<String> dict) {
if(s==null || s.length()==0)return true;
if(dict.size()==0)return false;
int n=s.length();
dp=new int[n];
Arrays.fill(dp,-1);
buildPrefixTree(dict);
return breaks(s,0,dict)==1;
}
int dp[];
PrefixTreeNode root;
int breaks(String s, int start, Set<String> dict)
{
if(start==s.length())return 1;
if(dp[start]!=-1)return dp[start];
for(int i=start;i<s.length();i++)
{
if(dict.contains(s.substring(start,i+1)))
{
dp[start]= breaks(s,i+1,dict);
if(dp[start]==1)return 1;
}
else if(PrefixTreeNode.contains(s.substring(start,i+1),0,root)==false)
{
dp[start]=0;
return 0;
}
}
return dp[start];
}
void buildPrefixTree(Set<String> dict)
{
root=new PrefixTreeNode('0');
for(String s:dict)
{
build(s,0,root);
}
}
void build(String s, int index, PrefixTreeNode node)
{
if(index==s.length())return;
for(PrefixTreeNode p:node.next)
{
if(p.val==s.charAt(index))
{
build(s,index+1,p);
return;
}
}
PrefixTreeNode newNode=new PrefixTreeNode(s.charAt(index));
node.next.add(newNode);
build(s,index+1,newNode);
}
}
class PrefixTreeNode
{
ArrayList<PrefixTreeNode> next;
char val;
PrefixTreeNode(char c)
{
val=c;
next=new ArrayList<PrefixTreeNode>();
}
static boolean contains(String s, int index, PrefixTreeNode node)
{
if(index==s.length())return true;
for(PrefixTreeNode p:node.next)
{
if(p.val==s.charAt(index))
{
boolean t=contains(s,index+1,p);
if(t)return true;
}
}
return false;
}
}
=========================================================
Word break II
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”].
遇到这种打印所有路径的问题最先考虑的就是dfs + path保存中间路径。 其实这里dp的作用更多的是保存已经遍历过的结果,ie memoization for recursive
[code]
public class Solution {
List<String> list;
HashMap<Integer, List<String>> dp;
int valid[];
public List<String> wordBreak(String s, Set<String> dict)
{
list=new ArrayList<String>();
if(s==null || s.length()==0 || dict.isEmpty())return list;
dp=new HashMap<Integer, List<String>>();
valid=new int[s.length()];
Arrays.fill(valid, -1);
StringBuffer path=new StringBuffer();
breaks(s,0,dict,path);
return list;
}
int breaks(String s, int start, Set<String> dict, StringBuffer path)
{
if(start==s.length())
{
list.add(path.toString().trim());
if(dp.containsKey(start)==false)
{
List<String> temp=new ArrayList<String>();
temp.add(new String());
dp.put(start, temp);
}
return 1;
}
if(valid[start]!=-1)
{
if(dp.containsKey(start))
{
for(String str:dp.get(start))
{
path.append(str);
breaks(s,s.length(),dict,path);
path.delete(path.length()-str.length(), path.length());
}
}
return valid[start];
}
valid[start]=0;
for(int i=start;i<s.length();i++)
{
String sub=s.substring(start,i+1);
if(dict.contains(sub))
{
sub=sub+" ";
path.append(sub);
if(breaks(s,i+1,dict,path)==1)
{
valid[start]=1;
if(dp.containsKey(start)==false)dp.put(start, new ArrayList<String>());
List<String> l=dp.get(i+1);
StringBuffer temp=new StringBuffer(sub);
for(String entry:l)
{
temp.append(entry);
dp.get(start).add(temp.toString());
temp.delete(temp.length()-entry.length(),temp.length());
}
}
path.delete(path.length()-sub.length(),path.length());
}
}
return valid[start];
}
}