題目描述:
給定一個非空字符串 s 和一個包含非空單詞列表的字典 wordDict,判定 s 是否可以被空格拆分爲一個或多個在字典中出現的單詞。
說明:
拆分時可以重複使用字典中的單詞。
你可以假設字典中沒有重複的單詞。
示例 1:
輸入: s = "leetcode", wordDict = ["leet", "code"]
輸出: true
解釋: 返回 true 因爲 "leetcode" 可以被拆分成 "leet code"。
示例 2:
輸入: s = "applepenapple", wordDict = ["apple", "pen"]
輸出: true
解釋: 返回 true 因爲 "applepenapple" 可以被拆分成 "apple pen apple"。
注意你可以重複使用字典中的單詞。
示例 3:
輸入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
輸出: false
分析思考:
1、要寫出來遞歸的做法
2、仔細分析重疊子問題
dp解法關鍵:兩次循環檢查從0-i之間每一個substring(0,j)和substring(j,i)是否在字典裏面,而前者是重疊的子問題,當且僅當第一個爲true且第二個也是true的時候才返回true,因爲一個字符串想要滿足true,必須拆成的兩部分分別都在在字典中才是符合條件的,所以需要檢查第一個字符串是重疊計算的子問題,可以通過動態規劃減少計算量
有兩個注意:dp[0] = 0,還有就是但凡遇到一個true就可以返回這個dp值爲true
貼上Java代碼:
class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
if ( s.length() <= 0 ) {
return true;
}
if ( wordDict.size() <= 0 ) {
return false;
}
int n = s.length();
if ( wordDict.size() == 1 ) {
return s.equals(wordDict.get(0));
}
//return helper(s , new HashSet(wordDict) , 0);
//動態規劃解法
boolean dp[] = new boolean[n+1];
dp[0] = true;
for( int i = 1 ; i <= n ; i++ ) {
dp[i] = false;
}
for ( int i = 1 ; i <= n ; i++ ) {
for( int j = 0 ; j <= i ; j++ ) {
//j等於i也可以,下面判斷不執行就是了
if ( dp[j] && wordDict.contains( s.substring(j,i)) ) {
dp[i] = true;
break;
}
}
}
return dp[n];
}
//遞歸(超時)
// public Boolean helper( String s , Set<String> wordDict , int start ) {
// if ( start == s.length() ) {
// return true;
// }
// for ( int end = start+1 ; end <= s.length() ; end++ ) {
// if ( wordDict.contains(s.substring(start,end))
// && helper(s,wordDict,end) ) {
// return true;
// }
// }
// return false;
// }
}