题目描述:
题解:
方法1:暴力搜索
最简单的实现方法是用递归去搜索。 针对一个字符串s,设它的任何一个子串是substr,如果substr在词典wordDict中出现过,那么返回一个true,然后将这个substr作为前缀的剩余部分回归调用。同时,如果某次函数调用中发现整个字符串都已经被拆分且在字典中出现过了,函数就返回true。
代码:
class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
return word_Break(s, wordDict, 0);
}
public boolean word_Break(String s, List<String> wordDict, int start) {
if (start == s.length()) {
return true;
}
for (int end = start + 1; end <= s.length(); end++) {
if (wordDict.contains(s.substring(start, end)) && word_Break(s, wordDict, end)==true) {
return true;
}
}
return false;
}
}
提交结果:
可以看到,使用暴力解法的运行时间会遇到一种极端情况
时间复杂度:O(n`n)。考虑最坏情况 s = {aaaaaaa}。每一个前缀都在字典中,此时搜索递归树的复杂度会达到 n`n
空间复杂度:O(n) 。回溯树的深度最深达到 n。
方法2:动态规划
使用动态规划求解,针对一个字符串s和一个字典wordDict,若字符串的长度为n,给定函数f(n)表示长度为n的字符串s能否被字典wordDict切分
那么f(i)表示前面长度为i的子字符串是否能被wordDict切分
针对前面长度为i的字符串,用一个下标j可以划分为子问题即(0,j)的部分和(j+1,i)的部分,若(0,j)可以被词典切分(即f(j)=true),且词典中包含(j+1,i)的部分,则f(i)=true
则状态方程为:
代码为:
class Solution {
//解法二:动态规划
public boolean wordBreak(String s,List<String> wordDict) {
int n = s.length();
boolean[] f = new boolean[n+1];
f[0]=true;
for(int i=1;i<=n;i++) {
for(int j=0;j<i;j++) {
if(f[j]==true && wordDict.contains(s.substring(j, i))) {
f[i]=true;
break;
}
}
}
return f[n];
}
}
提交结果: