《算法设计与分析》第十周作业
标签(空格分隔): 课堂作业
姓名:李**
学号:16340114
题目:Word Break(https://leetcode.com/problems/word-break)
题目概要
给定一个无分隔符的字符串和一个字典,问是否能将字符串分解成字典中含有的词。
思路
给定位置i,定义该下标"可分解"的含义为:从0到该下标的子字符串(不包括i)是可以被分解的。
要判断一个位置i是否可分解,就要判断上一个可分解的位置j到当前位置i(包含j不包含i)所分割形成的词是否在字典中,如果存在这样的j,那么位置i就是可分解的,如果不存在,那么位置i就是不可分解。最终答案就是下标为字符串长度L的位置是否可分解。
用符号的方式有点难说清楚,举个例子就好了。字符串为"helloworld",位置0是可分解的,因为下标为0的位置之前是长度为0的串,自然可以分解,位置5是可分解的,下标为5的为w,w前的可分解位置是0,从0到5(包含0不包含5)形成的词为hello。这样就应该清楚以可分解位置为下标的词应该归到下一词的开头,而不是上一个词的结尾。
由此推出状态迁移方程为:
具体实现
下标为0的位置是可分解的,因为0位置前的空子字符串是可分解的,所以把valid[0]设为true,其他位置的值设为false,然后根据状态转移方程写就好了。
心得
这道题在课堂上讲过,我觉得动手来实现一遍可以加深印象和对动态规划的理解。我现在对动态规划的认识似乎比上一周领略的要更好一点,像word break这一类型的动态规划问题,先考虑一个任意位置i,用某种规则从位置i往前找j,根据前面的j的状态确定当前位置i的状态。课本习题的开餐厅那题也是这个思想。下一周想挑战一下这道题的升级版,希望能对动态规划有更深的认识。
源码:
#define isValid(word) (find(wordDict.begin(), wordDict.end(), word) == wordDict.end() ? false : true)
class Solution
{
public:
bool wordBreak(string s, vector<string>& wordDict)
{
int length = s.length();
bool* validEndAt = new bool [length+1];
for (int i = 0; i < length+1; ++i)
validEndAt[i] = false;
validEndAt[0] = true;
for (int i = 1; i <= length; ++i)
{
for (int j = i-1; j >= 0; --j)
{
if (validEndAt[j])
{
int lengthOfWord = i - j;
string word = s.substr(j, lengthOfWord);
if (isValid(word))
{
validEndAt[i] = true;
break;
}
}
}
}
return validEndAt[length];
}
};