LeetCode-139-单词拆分
题目
给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。
说明:
拆分时可以重复使用字典中的单词。
你可以假设字典中没有重复的单词。
示例 1:
输入: s = "leetcode", wordDict = ["leet", "code"]
输出: true
解释: 返回 true 因为 "leetcode" 可以被拆分成 "leet code"。
示例 2:
输入: s = "applepenapple", wordDict = ["apple", "pen"]
输出: true
解释: 返回 true 因为 "applepenapple" 可以被拆分成 "apple pen apple"。
注意你可以重复使用字典中的单词。
示例 3:
输入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
输出: false
思路
这道题在LeetCode里面属于动态规划,不过我把这道题强行做成了递归+分治。。
我的思路是这样的,字符串S可以被拆分成两个字符串S1、S2,如果两个字符串都可以被字典匹配,那么该字符串就可以被匹配,我们假设F(i, j)表示从 i 到 j 的字符串可以被匹配,那么就有以下表达式:
[F[0,i]=F[0,j].and.F[j,i]..0<j<i
]
表达式写的不是很好,大概意思就是设定一个for循环,j从0到i进行判断,如果有一组F[0,j]和F[j,i]满足条件,那么该字符串就满足条件;
另外,这里面会造成对一个字符串的子串多次截取与判断,就会特别耗时间,所以设定一个二维数组dp,保存字符串的开始与结束,第一次判断的时候保存判断结果,后续直接读取就好了;
最后,运行结果时间效率还不错,有61%,代码如下:
代码
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
// 保存子串判断结果,0表示为判断,1表示该子串在字典,-1表示该子串不在字典
int dp[100][100];
string word;
// 字典的hash表
unordered_map<string, bool> wordHash;
bool solve(int begin, int end){
string str = word.substr(begin, end-begin);
if (wordHash.find(str) != wordHash.end())
{
dp[begin][end] == 1;
return true;
}
dp[begin][end] = -1;
for (int i=begin+1; i<end; i++)
{
if (dp[begin][i] ==1 && dp[i][end] == 1)
return true;
else if (dp[begin][i]==-1 || dp[i][end]==-1 )
continue;
else
{
if (solve(begin, i) && solve(i, end))
return true;
}
}
return false;
}
bool wordBreak(string s, vector<string>& wordDict) {
// 创建字典的hash表
for (string str:wordDict)
wordHash[str] = true;
word = s;
return solve(0, s.length());
}
};
int main()
{
Solution su;
string s = "ab";
string dict[5] = {"a","b"};
vector<string> wordDict(dict, dict+2);
cout<<su.wordBreak(s, wordDict);
return 0;
}