【DP经典问题】WordBreak

这个题解法很多,顺便理一下思路

DP几步走:

1. 写状态转移方程,根据方程就可以得到基本DP方法,注意时间复杂度和空间复杂度的计算。


2.很多DP划分方式很多,所以注意使用记忆搜索来优化DP的处理速度。


3. 事实上使用DP递归调用仍然使用了大量的存储空间,使用DP自底向上可以实现O(1)存储的实现,但往往那个稍显困难。


Word Break这题接法很多,最笨的接法是直接DP,


解法1: 直接DP.

既然要把一个String s转化为多个单词的组合,可以从头向尾匹配一个一个字符匹配,即(参考WordBreakS2)

solve(int start){
	for(int i=start;i>=s.length ();i++){
			String tmp=st.substring(start,i);
			if(sset.contains(tmp)){
			    solve(i);
			}
		}
}	

但这有问题,dict里面出现a,aa,aaa,aaaa绝对超时,因为会重复查找,因此为了避免重复计算,最常用的方法就是记忆搜索。用数组存储中间结果。

解法2:记忆搜索+DP res存结果 0为没存结果,-1为false,1为正确,其实1不用存。

320ms过大集合


Set<String> sset;
	String st;
	int[] res;
	private boolean dp1(int start){
		if(res[start]!=0){
			if(res[start]>0)
				return true;
			else
				return false;
		}
		boolean success=false;
		for(int i=st.length();i>=start+1;i--){
			String tmp=st.substring(start,i);
			//System.out.println("tmp=["+start+","+i+"]"+tmp);
			if(sset.contains(tmp)){
				if(i==st.length()){
					res[start]=1;
					return true;
					
				}
				else
					success=dp1(i);
			}
			if(success){
				res[start]=1;
				 return true;
			}
				
		}
		res[start]=-1;
		return false;
		
	}
	
	public boolean wordBreak(String s, Set<String> ss) {
		sset=ss;
		st=s;
		res=new int[s.length()+10];
		return dp1(0);
		
	}


这就是我的能力极限了,最近看到很多大牛谈到bottom up的DP,很是神往,参考了一些资料。

http://sobuhu.com/algorithm/2012/12/19/dynamic-programming-1.html

http://pisces.ck.tp.edu.tw/~peng/index.php?action=showfile&file=ffea8e9bf9695ed5ccc35eb71d3b2ac6175cab78a


顺便比较一下神写的代码和渣写的代码

public class Solution {
    public boolean wordBreak(String s, Set<String> dict) {
             return wordBreakHelper(s, dict, 0);
    }
 
    public boolean wordBreakHelper(String s, Set<String> dict, int start){
        if(start == s.length()) 
            return true;
 
        for(String a: dict){
            int len = a.length();
            int end = start+len;
 
            //end index should be <= string length
            if(end > s.length()) 
                continue;
 
            if(s.substring(start, start+len).equals(a))
                if(wordBreakHelper(s, dict, start+len))
                    return true;
        }
 
        return false;
    }
}


解法3:神代码  似乎还是记忆搜索

public class Solution {
    public boolean wordBreak(String s, Set<String> dict) {
        boolean[] t = new boolean[s.length()+1];
        t[0] = true; //set first to be true, why?
        //Because we need initial state
 
        for(int i=0; i<s.length(); i++){
            //should continue from match position
            if(!t[i]) 
                continue;
 
            for(String a: dict){
                int len = a.length();
                int end = i + len;
                if(end > s.length())
                    continue;
                if(s.substring(i, end).equals(a)){
                    t[end] = true;
                }
            }
        }
 
        return t[s.length()];
    }
}
这个方法实际还是dp的记忆搜索,从头节点开始遍历,能走到的点标记true,看看尾节点能不能标记true。一定要注意,处理这种单词类型的时候一定要想好遍历的基本单位是什么,到底是一个一个字符走,还是一个一个单词走。想清楚,才能走的更快



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值