題目
給定一個非空字符串 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
鏈接:https://leetcode-cn.com/problems/word-break
解題記錄
- 將wordDict存入set中進行比較
- 通過構建不同長度的字符串進行比較
/**
* @author ffzs
* @describe
* @date 2020/6/25
*/
public class Solution2 {
static int max = 0, min = Integer.MAX_VALUE;
public static boolean wordBreak(String s, List<String> wordDict) {
Set<String> wordSet = new HashSet<>();
for (String s1 : wordDict) {
wordSet.add(s1);
max = Math.max(max, s1.length());
min = Math.min(min, s1.length());
}
return wordBreak(s, 0, wordSet);
}
private static boolean wordBreak (String s, int start, Set<String> wordSet) {
if (start == s.length()) return true;
else {
for (int i = Math.min(s.length(), start+max); i >= start + min; -- i) {
if (wordSet.contains(s.substring(start, i)) && wordBreak(s, i, wordSet)) {
return true;
}
}
}
return false;
}
public static void main(String[] args) {
String s = "aaaaaaa";
List<String> wordDict = new ArrayList<>(List.of(new String[]{"aaaa", "aaa"}));
System.out.println(wordBreak(s, wordDict));
}
}
暴力解法沒成,超時了。。。
優化
通過使用動態規劃進行對狀態進行記錄
- 通過一個step數組記錄目標字符串可以通過字典中字符串拼接到的位置
- 起始狀態是step[0]=true
- 轉成set進行查找比list快很多
/**
* @author ffzs
* @describe
* @date 2020/6/25
*/
public class Solution3 {
static int max = 0, min = Integer.MAX_VALUE;
public static boolean wordBreak(String s, List<String> wordDict) {
Set<String> wordSet = new HashSet<>();
boolean[] step = new boolean[s.length()+1];
step[0] = true;
for (String s1 : wordDict) {
wordSet.add(s1);
max = Math.max(max, s1.length());
min = Math.min(min, s1.length());
}
for (int i = 0; i <= s.length()-min+1; i++) {
for (int j = i + min; j <= s.length() && j <= i + max; j++) {
if (step[i]) {
if (wordSet.contains(s.substring(i, j))){
step[j] = true;
}
}
}
}
return step[s.length()];
}
public static void main(String[] args) {
String s = "aaaaaaa";
List<String> wordDict = new ArrayList<>(List.of(new String[]{"aaa", "aaaa"}));
System.out.println(wordBreak(s, wordDict));
}
}
- 通過使用HashMap對字典中的字符串通過第一個字符進行存儲
- 更改比對的邏輯,通過第一個字符獲取到對應的字符串數據
- 動態規劃的邏輯是一樣的
- 匹配到最後,能夠拼成長度爲s.length則返回true否者返回false
/**
* @author ffzs
* @describe
* @date 2020/6/25
*/
public class Solution4 {
public static boolean wordBreak(String s, List<String> wordDict) {
Map<Character, List<String>> map = new HashMap<>();
char[] seq = s.toCharArray();
for (String s1 : wordDict) {
Character f = s1.charAt(0);
if (!map.containsKey(f)){
List<String> l = new ArrayList<>();
l.add(s1);
map.put(f, l);
}else{
map.get(f).add(s1);
}
}
boolean[] step = new boolean[seq.length + 1];
step[0] = true;
for (int i = 0; i < seq.length ; i++) {
if (step[i] && map.containsKey(seq[i])){
for (String s1 : map.get(seq[i])) {
if (isMatch(seq, s1, i)) {
if (i+s1.length() == seq.length) return true;
step[i+s1.length()] = true;
}
}
}
}
return false;
}
private static boolean isMatch (char[] seq, String s, int start) {
if (start + s.length() > seq.length) return false;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) != seq[start+i]) return false;
}
return true;
}
public static void main(String[] args) {
String s = "leetcode";
List<String> wordDict = new ArrayList<>(List.of(new String[]{"leet", "code"}));
System.out.println(wordBreak(s, wordDict));
}
}