给定一个非空字符串 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 思路:
算法思想就是动态规划,dp[i]的含义为s的前i个字母组成的子串是否可以被拆分为字典中的单词。
大致思路:
以“leetcode”为例,字典为“leet”和“code”,显然dp[4]为true,我们要的是dp[8] (即dp[sLen])
观察可知dp[8]可以由dp[4]和字典推导来,就是知道了dp[4]为true,从s+4开始,枚举看之后的单词是否能与
字典匹配。
代码:C:
1 bool wordBreak(char * s, char ** wordDict, int wordDictSize){ 2 int sLen = strlen(s); 3 bool dp[sLen + 1]; 4 memset(dp, false, sizof(dp)); 5 dp[0] = true; /* 初始化,以便状态转移 */ 6 for (int i = 1; i <= sLen; i++) /* 从s的第一个字母开始枚举 */ 7 /* 枚举到第i个字母时,i之前的dp已经全部算出来了,我们再枚举字典中的单词,根据每个单词的 8 长度决定分割点,假设分割点是k,当分割点后的子串能与字典单词匹配且dp[k]为true,则dp[i]为true 9 */ 10 for (int j = 0; j < wordDictSize; j++) { 11 int len = strlen(wordDict[j]); 12 int k = i - len; /* 分割点是由i和字典单词长度决定的 */ 13 if (k < 0) 14 continue; 15 dp[i] = (dp[k] && !strncmp(s + k, wordDict[j], len)) || dp[i]; 16 /* 这里注意要限制长度,故用strncmp */ 17 /* 进一步追求速度可用哈希法等代替strncmp */ 18 } 19 20 return dp[sLen]; 21 }
C++:
1 class Solution { 2 public: 3 bool wordBreak(string s, vector<string>& wordDict) { 4 if (s.empty() || wordDict.empty()) return false; 5 int n = s.size(); 6 vector<bool> dp(n + 1, false); 7 dp[0] = true; 8 for (int end = 1; end <= n; end++) { 9 for (int begin = 0; begin < end; begin++) { 10 if (dp[begin] && find(wordDict.begin(), wordDict.end(), 11 s.substr(begin, end - begin)) != wordDict.end()) { 12 dp[end] = true; 13 break; 14 } 15 } 16 } 17 return dp[n]; 18 } 19 };
原文地址:https://www.cnblogs.com/ccllcc/p/12530848.html
时间: 2024-10-07 10:23:18