leecode更新
This commit is contained in:
parent
2d33b78f2c
commit
5f1ccb4541
|
|
@ -0,0 +1,153 @@
|
|||
package com.markilue.leecode.dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @BelongsProject: Leecode
|
||||
* @BelongsPackage: com.markilue.leecode.dynamic
|
||||
* @Author: markilue
|
||||
* @CreateTime: 2022-12-08 10:38
|
||||
* @Description:
|
||||
* TODO 力扣139题 单词拆分:
|
||||
* 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。
|
||||
* 注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class T17_WordBreak {
|
||||
|
||||
@Test
|
||||
public void test(){
|
||||
String s = "leetcode";
|
||||
|
||||
List<String> wordDict = new ArrayList<>(Arrays.asList("leet", "code"));
|
||||
System.out.println(wordBreak(s,wordDict));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1(){
|
||||
String s = "applepenapple";
|
||||
|
||||
List<String> wordDict = new ArrayList<>(Arrays.asList("apple", "pen"));
|
||||
System.out.println(wordBreak(s,wordDict));
|
||||
}
|
||||
|
||||
/**
|
||||
* 思路:实际上就是判断能重复用的wordDict能否构造出s
|
||||
* TODO 动态规划五部曲:
|
||||
* (1)dp定义:dp[i][j]使用[0-i]的wordDict能否构造出s[0-j]
|
||||
* (2)dp状态转移方程:dp[j]=dp[j]||(dp[j-wordDict[i].length]&&wordDict[i]==s.subString(j-wordDict[i].length))
|
||||
* (3)dp初始化:dp[0]=true
|
||||
* (4)dp遍历顺序:跟两个for的顺序有关系,因为word可以反复利用,只需要判断最后的word
|
||||
* (5)dp举例推导:
|
||||
* 速度击败71.72%,内存击败60.22%
|
||||
* @param s
|
||||
* @param wordDict
|
||||
* @return
|
||||
*/
|
||||
public boolean wordBreak(String s, List<String> wordDict) {
|
||||
boolean[] dp = new boolean[s.length()+1];
|
||||
dp[0]=true;
|
||||
|
||||
|
||||
for (int j = 0; j < dp.length; j++) {
|
||||
for (int i = 0; i < wordDict.size(); i++) {
|
||||
String word = wordDict.get(i);
|
||||
if(j>=word.length()){
|
||||
String b = s.substring(j-word.length(),j);
|
||||
dp[j]=dp[j]||(dp[j-word.length()]&&word.equals(b));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return dp[s.length()];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 官方另一种背包,找到之后直接break是精髓,但是就看不出dp的状态转移方程了
|
||||
* 速度击败92.41%,内存击败87.5%
|
||||
* @param s
|
||||
* @param wordDict
|
||||
* @return
|
||||
*/
|
||||
public boolean wordBreak2(String s, List<String> wordDict) {
|
||||
boolean[] dp = new boolean[s.length() + 1];
|
||||
dp[0] = true;
|
||||
|
||||
for (int i = 1; i <= s.length(); i++) {
|
||||
for (String word : wordDict) {
|
||||
int len = word.length();
|
||||
if (i >= len && dp[i - len] && word.equals(s.substring(i - len, i))) {
|
||||
dp[i] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dp[s.length()];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 官方及代码随想录的的动态规划解法,利用hashset加快速度
|
||||
* 速度击败33.98%,内存击败7.9%
|
||||
* @param s
|
||||
* @param wordDict
|
||||
* @return
|
||||
*/
|
||||
public boolean wordBreak1(String s, List<String> wordDict) {
|
||||
HashSet<String> set = new HashSet<>(wordDict);
|
||||
boolean[] valid = new boolean[s.length() + 1];
|
||||
valid[0] = true;
|
||||
|
||||
for (int i = 1; i <= s.length(); i++) {
|
||||
for (int j = 0; j < i && !valid[i]; j++) {
|
||||
if (set.contains(s.substring(j, i)) && valid[j]) {
|
||||
valid[i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return valid[s.length()];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 回溯+记忆化搜索:本质上就是把已经用过的东西存起来,便于剪枝
|
||||
* 速度击败79.1%,内存击败24.38%
|
||||
*/
|
||||
private Set<String> set;
|
||||
private int[] memo;
|
||||
public boolean wordBreak3(String s, List<String> wordDict) {
|
||||
memo = new int[s.length()];
|
||||
set = new HashSet<>(wordDict);
|
||||
return backtracking(s, 0);
|
||||
}
|
||||
|
||||
public boolean backtracking(String s, int startIndex) {
|
||||
// System.out.println(startIndex);
|
||||
if (startIndex == s.length()) {
|
||||
return true;
|
||||
}
|
||||
if (memo[startIndex] == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = startIndex; i < s.length(); i++) {
|
||||
String sub = s.substring(startIndex, i + 1);
|
||||
// 拆分出来的单词无法匹配
|
||||
if (!set.contains(sub)) {
|
||||
continue;
|
||||
}
|
||||
boolean res = backtracking(s, i + 1);
|
||||
if (res) return true;
|
||||
}
|
||||
// 这里是关键,找遍了startIndex~s.length()也没能完全匹配,标记从startIndex开始不能找到
|
||||
memo[startIndex] = -1;//关键在于这里,添加了记忆,即从startIndex开始是不能找到,以后到这就不用继续往下回溯了
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue