LeetCode139:一个字符串是否由字典的中的字段一个或者多个拼接成。

这道题,我很伤心,因为我没有很好的思路,先说下我的递归吧,从开头匹配,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);

		}

	}

}

哈哈

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值