标签:problems 字典 慢慢 集中 etc 一个 循环 -- hashset
这个题要求我们去检查s是否能拆分成字典集合中的单词,其中字典集中可以把重复出现的单词看做一个。
我们仔细看第三个测试用例,可以发现他说的拆分就是你一个字母不能同时属于两个新单词。
这个题第一次做不会,后来看了题析才知道是DP问题,今天这个题作为每日一题, 自然而然可以秒杀了。
我们定义一个boolean数组,如果字符串的子串substring(j,i)可以拆分成字典集合里面的单词,我们就将dp[i]置为true.
当然这个也是有个前提的,这个拆分的前一个字符必须也能被拆分成另外一个单词,否则我们当前的拆分可能是重复利用了同一个字符。
class Solution {
/**
* LC 139.单词拆分
* 传统DP问题
* 2020年6月25日
* @param s
* @param wordDict
* @return
*/
public boolean wordBreak(String s, List<String> wordDict) {
//注意,这里必须要长一位,因为0号位会被作为标志位来使用。
boolean[] dp = new boolean[s.length()+1];
//dp[0]其实就是空字符串,空字符串必定在另外一个非空字符串的集合中。
dp[0] = true;
//外层的i用于控制当前字符串的右边界,所以会是小于等于s.length()
for(int i = 1; i <= s.length(); i++){
//内层的j用于控制左边界,慢慢去收缩这个边界。
for(int j = 0; j < i; j++){
//注意!这里判断条件有两个,第一个是当前剪切下来的字符串在字典中是否存在
//第二个是要检查我们dp[j]就是我们的前一位字符是否被正确匹配,如果这个不成立
//说明我们可能重复利用了某个字符,这样会导致单词划分有了重复。
if(dp[j] && wordDict.contains(s.substring(j,i))){
dp[i] = true;
break;
}
}
}
//返回最后那个位置的值
return dp[s.length()];
}
}
做完后又详细看了下评论区,真的挺NB的,我的实现代码是没有经过任何剪枝的,导致只击败了20%左右的人。但是这个题其实可以剪枝剪的很厉害,例如:
通过以上的剪枝操作,我们可以将代码优化到击败99%的人。
class Solution {
/**
* LC 139.单词拆分
* 传统DP问题
* 2020年6月25日
* @param s
* @param wordDict
* @return
*/
public boolean wordBreak(String s, List<String> wordDict) {
int len = s.length(), maxw = 0, minw = Integer.MAX_VALUE;
boolean[] dp = new boolean[len + 1];
dp[0] = true;
Set<String> set = new HashSet();
for(String str : wordDict){
set.add(str);
maxw = Math.max(maxw, str.length());
minw = Math.min(minw, str.length());
}
for(int i = minw; i < len + 1; i++){
for(int j = i; j >= 0 && j >= i - maxw; j--){
if(dp[j] && set.contains(s.substring(j, i))){
dp[i] = true;
break;
}
}
}
return dp[len];
}
}
标签:problems 字典 慢慢 集中 etc 一个 循环 -- hashset
原文地址:https://www.cnblogs.com/ZJPaang/p/13191162.html