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