单词拆分题目的思路探讨与源码
单词拆分的题目如下图,该题属于动态规划法的题目,主要考察对于动态规划和剪枝法的理解和认识,结合当前状态信息和历史结果就可以进行判断。本文的题目作者想到2种方法,第二种方法是第一种方法的优化,本质上两种方法都是动态规划DP,第一种方法使用java写、第二种方法使用Python写,当然这应该不是最优的解法,还希望各位大佬给出更快的算法。
本人认为该题目可以使用动态规划的方法,假设在循环遍历的时候,每次判断需要两个条件联合判断,一个是历史结果信息,也就是历史的判断必须是字符串s都在字典里;一个是当前状态信息,也就是从当前下标都下一个下标的子字符串必须在字典里,满足这两个条件就可以进行遍历和判断,从而达到判断整个字符串s是否在dict字典里面。所以按照这个思路我们的代码按照公式如下:
#喷火龙与水箭龟
class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
int sLen = s.length();
boolean[] wb = new boolean[sLen + 1];
wb[0] = true;
for(int ij=0;ij<sLen;ij++){
for(int jk=ij+1;jk<(sLen+1);jk++){
if(wb[ij] && wordDict.contains(s.substring(ij,jk))){
wb[jk] = true;
}
}
}
return wb[sLen];
}
}
显然,这种直接使用动态规划的思路不是最优的,因此我们在这个基础上进行剪枝,把字典里面最长的单词拿出来作为限制,如果在历史的子字符串都没有匹配上,并且已经超过了最大的单词长度,那么剩下的单词就算匹配上也是不匹配,所以直接返回False即可,下面是Python代码部分:
#喷火龙与水箭龟
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
sLen = len(s)
pos = [False]*(sLen+1)
pos[0] = True
maxNum = -1
dcSet = set(wordDict)
for mk in wordDict:
maxNum = max(len(mk),maxNum)
for ij in range(1,sLen+1):
for jk in range(ij,ij-sLen,-1):
if(jk>0 and (s[jk-1:ij] in dcSet)):
pos[ij] = pos[ij] | pos[jk-1]
return pos[sLen]
从结果来说是比较一般的,因为时间复杂度其实是接近O(n^2) ,但是通过剪枝肯定可以进一步提速,希望朋友们能够多多指教,非常感谢。