这道题,我很伤心,因为我没有很好的思路,先说下我的递归吧,从开头匹配,applepen 则先匹配apple,然后用pen和字典在匹配,直到所有的可以匹配完。但这样迭代的浪费空间问题没有解决,在这里绊了一段时间,然后改进,时间是快了。题目如下:
Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if s can be segmented into a space-separated sequence of one or more dictionary words.
Note:
- The same word in the dictionary may be reused multiple times in the segmentation.
- You may assume the dictionary does not contain duplicate words.
Example 1:
Input: s = "leetcode", wordDict = ["leet", "code"] Output: true Explanation: Return true because"leetcode"
can be segmented as"leet code"
.
Example 2:
Input: s = "applepenapple", wordDict = ["apple", "pen"] Output: true Explanation: Return true because"
applepenapple"
can be segmented as"
apple pen apple"
. Note that you are allowed to reuse a dictionary word.
Example 3:
Input: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
Output: false
2021年6月24号
1、动态规划:超时,大量重复的工作
//这个字符要不要按照这种拆分
public boolean wordBreak(String s, List<String> wordDict) {
int len =wordDict.size();
Deque<String> q=new LinkedList<>();
q.push(s);
while(q.size()>0){
String t=q.pop();
for(int i=0;i<len;i++){
if(t.equals(wordDict.get(i))) {
return true;
}
if(t.startsWith(wordDict.get(i))){
q.push(t.substring(wordDict.get(i).length()));
}
}
}
return false;
}
迭代---也是大量重复的工作
//对于数组的每个元素,要不要
public boolean wordBreak2(String s, List<String> wordDict) {
int len=wordDict.size();
for(int i=0;i<len;i++){
if(s.equals(wordDict.get(i))) {
return true;
}
if(s.startsWith(wordDict.get(i))){
boolean tret=wordBreak2(s.substring(wordDict.get(i).length()),wordDict);
if(tret){
return true;
}
}
}
return false;
}
动态规划---保存结果
//对于每一个从i开始的数组的每个元素,要不要
public boolean wordBreak3(String s, List<String> wordDict) {
int len=wordDict.size();
int slen=s.length();
int[] p=new int[slen];
for(int i=0;i<slen;i++){
if(i>0&&p[i-1]==0){ //到不了--就没必要继续
continue;
}
String t=s.substring(i);
for(int k=0;k<len;k++){
if(t.startsWith(wordDict.get(k))){
p[i+wordDict.get(k).length()-1]=1;
if(p[slen-1]!=0){
return true;
}
}
}
}
return false;
}
--------------------------------------------------以前的理解
我的解法:
package leetcode;
import java.util.ArrayList;
import java.util.List;
//其实我拿到这道题,是真的没有思路的,可能动态规划的核心,我还没懂吧,我的思路就是,从头开始一个一个的去比对字典,如果可以就用,如果不可以则返回,直到结果为0;
public class LC139WordBreak {
public boolean wordBreak(String s, List<String> wordDict) {
if(s.length()==0){
return true;
}
for(int i=0;i<wordDict.size();i++){
String w=wordDict.get(i);
if(s.indexOf(w)==0){
String s1=s.substring(w.length(),s.length());
while(s1.indexOf(w)==0){
s1=s1.substring(w.length(),s1.length());
}//这个是我自己预防超时的一个办法,但其实我自己都认为他不是一个很严谨的办法,当时一直超时
//,其实是利用的空间太多了,但我选择素数7试了试,结果只不过由我们的3+4的推断,变成了,4+3而已
//,还是能跑到这个过程的,因此应该是没有问题的。其实也是间接地实现了,先匹配最长的。
boolean ret=wordBreak(s1,wordDict);
if(ret){
return true;
}
}
}
return false;
}
public static void main(String[] args) {
LC139WordBreak t = new LC139WordBreak();
String s= "aaaaaaaba";
List<String> wordDict = new ArrayList<String>();
wordDict.add("aa");
wordDict.add("aaa");
wordDict.add("aaaa");
wordDict.add("ba");
System.out.println(t.wordBreak(s, wordDict));
}
}
接下来的是:动态规划的核心:记录前一状态,利用前一状态,生成当前状态。具体代码如下:
package leetcode;
import java.util.ArrayList;
import java.util.List;
public class LC139WordBreakIII {
public boolean wordBreak(String s, List<String> wordDict) {
int len=s.length();
boolean[] ret= new boolean[len+1]; //这个是用的很巧的
int max=0;
for(String w : wordDict){
if(w.length()>max){
max=w.length();
}
}
ret[0]=true;
for(int i=1;i<=len;i++){
for(int j=i-1;j>=0&&i-j<=max;j--){
if(ret[j] && wordDict.contains(s.substring(j, i))){
ret[i]=true;//你想知道第i的状态,你需要知道i减去的第一单词的状态,减去第二个的状态,依次类推。这一部分也可以换种写法的。
break;
}
}
}
return ret[len];
}
public static void main(String[] args) {
LC139WordBreakIII t = new LC139WordBreakIII();
String s= "aaaaaaaaba";
List<String> wordDict = new ArrayList<String>();
wordDict.add("aa");
wordDict.add("aaa");
wordDict.add("aaaa");
wordDict.add("ba");
System.out.println(t.wordBreak(s, wordDict));
}
}
其实第一种的运行时间,比第二种的要短,其实我觉得可能是while循环那一段。
这一部分换成另一种的写法是:我觉得这个是最容易理解的:具体代码如下:
class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
int len=s.length();
boolean[] ret= new boolean[len+1];
//ret[0]=true;
for(int i=0;i<len;i++){
for(int k=0;k< wordDict.size();k++){
String s1 =wordDict.get(k);
int l1=s1.length();
if(i+l1<=len && (i==0 ||ret[i-1] )){
if(ret[i+l1-1]){
continue;
}
if(s.substring(i, i+l1).equals(s1)){
ret[i+l1-1]=true;
}
}
}
}
return ret[len-1];
}
}
想把所有的可能分割结果输出,代码如下:这就是140的答案,但是这道题我被困住了,因为我还在线中国和不可能是这种办法,会超时,哎,愚蠢的我呀!!还在延续上面的办法。谨记
package leetcode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class LC140WordBreakVI {
public List<String> wordBreak(String s, List<String> wordDict) {
List<String> ret = new ArrayList<String>();
Map<String,List<String>> map= new HashMap<String,List<String>>();
ret= getBack(s,wordDict,map);
return ret;
}
public List<String> getBack(String s, List<String> wordDict, Map<String, List<String>> map) {
if(map.containsKey(s)){
return map.get(s);
}
List<String> res = new ArrayList<String>();
for(int i=0;i<s.length();i++){
String temp=s.substring(0, i+1);
if(wordDict.contains(temp)){
if(i==s.length()-1){
res.add(temp);
}else{
List<String> rlist=getBack(s.substring(i+1),wordDict,map);
for(String w : rlist){
res.add( temp+' '+ w);
}
}
}
}
map.put(s, res);
return res;
}
public static void main(String[] args) {
LC140WordBreakVI t = new LC140WordBreakVI();
String s = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
//System.out.println(s.length());
List<String> wordDict = new ArrayList<String>();
wordDict.add("a");
wordDict.add("aa");
wordDict.add("aaa");
wordDict.add("aaaa");
wordDict.add("aaaaa");
wordDict.add("aaaaaa");
wordDict.add("aaaaaaa");
wordDict.add("aaaaaaaa");
wordDict.add("aaaaaaaaa");
wordDict.add("aaaaaaaaaa");
List<String> ret = t.wordBreak(s, wordDict);
System.out.println(ret.size());
for (String str : ret) {
System.out.println(str);
}
}
}
哈哈