题目描述
给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。
注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。字典中的所有单词互不相同。
例子:
输入: s = "applepenapple", wordDict = ["apple", "pen"]
输出: true
解释: 返回 true 因为 "applepenapple" 可以由 "apple" "pen" "apple" 拼接成。
注意,你可以重复使用字典中的单词。
解题思路
由于此题可以拆分为子问题,所以可用动态规划解题。关键是找出递推关系。
如下图,假设数组dp[i] 表示 长度为 i 的字符串是否能由字典中单词组成。当我们用下标j将s划分为两个子串s[0:j]和s[j+1:i]时,dp[i]主要取决于两点:
- 他的前缀子串s[0:j]即dp[j],是否为true
- 剩余子串s[j+1:i]是否在单词表中。
即 dp[i] = dp[j] && check(s[j+1:i])。
解题代码
bool wordBreak(char* s, char** wordDict, int wordDictSize)
{
int len = strlen(s);
bool *dp = (bool *)malloc(sizeof(bool) * (len+1));
memset(dp, 0, sizeof(bool) * (len+1));
dp[0] = true;
int i, j;
for (i=1; i<=len; ++i)
{
for (j=0; j<wordDictSize; ++j) // 遍历字典比遍历0-i快
{
int wordLen = strlen(wordDict[j]);
int k = i - wordLen;
if (k < 0)
continue;
if (dp[k] && 0 == strncmp(s+k, wordDict[j], wordLen)) // 当且仅当dp[k] == true 和 s[k, i]在字典中, dp[i] = true
{
dp[i] = true;
break;
}
}
}
bool ret = dp[len];
free(dp);
return ret;
}