【算法与数据结构】139、LeetCode单词拆分

文章目录

所有的LeetCode题解索引,可以看这篇文章------【算法和数据结构】LeetCode题解

一、题目

二、解法

  思路分析:本题可以看做一个动态规划问题。其中,字符串s是背包,而字典中的单词就是物品。题目问的是单词能否组成字符串s,就是问物品能不能把背包装满。字典中的单词可以重复使用,因此是一个完全背包问题。

  • 第一步, d p j dpj dpj的含义。 d p j dpj dpj代表的是字符串长度为 j j j时,该能否由字典中的单词构成。如果能,则为true。

  • 第二步,递推公式。如果确定 d p j dpj dpj是true,且 j , i j, i j,i这个区间的子串出现在字典里,那么 d p i dpi dpi一定是true。 ( j < i ) (j < i ) (j<i)。所以递推公式是:

    cpp 复制代码
    if(dp[j] &&  [j, i]这个区间的子串出现在字典里) dp[i] = true
  • 第三部,元素初始化。 d p 0 dp0 dp0初始化为1。

  • 第四部,递归顺序。本题严格划分起来是一个排列问题。以s = "applepenapple", wordDict = "apple", "pen" 为例。我们要求 物品的组合一定是 "apple" + "pen" + "apple" 才能组成 "applepenapple"。"apple" + "apple" + "pen" 或者 "pen" + "apple" + "apple" 是不可以的,那么我们就是强调物品之间顺序。所以说,本题一定是先遍历背包,再遍历物品。

  • 第五步,打印结果。
      为了判断 j , i j, i j,i这个区间的子串出现在字典里,我们构建了一个无序集合。其底层实现是一个哈希表,可以在常数时间内( O ( 1 ) O(1) O(1))内进行查找。
      程序如下:

cpp 复制代码
class Solution {
public:
	bool wordBreak(string s, vector<string>& wordDict) {
		unordered_set<string> wordSet(wordDict.begin(), wordDict.end());
		vector<bool> dp(s.size() + 1, 0);
		dp[0] = 1;
		for (int i = 1; i <= s.size(); i++) {	// 遍历背包(字符串s)
			for (int j = 0; j < i; j++) {		// 遍历物品(单词)
				string key = s.substr(j, i - j);
				if (dp[j] && wordSet.find(key) != wordSet.end()) {
					dp[i] = 1;
				}
			}
		}
		return dp[s.size()];
	}
};

复杂度分析:

  • 时间复杂度: O ( n 3 ) O(n^3) O(n3)。除了两层循环以外,还有需要substr返回子串,它是O(n)的复杂度(这里的n是substring的长度)。
  • 空间复杂度: O ( n ) O(n) O(n)。

三、完整代码

cpp 复制代码
# include <iostream>
# include <vector>
# include <string>
# include <unordered_set>
using namespace std;

class Solution {
public:
	bool wordBreak(string s, vector<string>& wordDict) {
		unordered_set<string> wordSet(wordDict.begin(), wordDict.end());
		vector<bool> dp(s.size() + 1, 0);
		dp[0] = 1;
		for (int i = 1; i <= s.size(); i++) {	// 遍历背包(字符串s)
			for (int j = 0; j < i; j++) {		// 遍历物品(单词)
				string key = s.substr(j, i - j);
				if (dp[j] && wordSet.find(key) != wordSet.end()) {
					dp[i] = 1;
				}
			}
		}
		return dp[s.size()];
	}
};

int main() {
	string s = "catsandog";
	vector<string> wordDict = { "cats", "dog", "sand", "and", "cat" };
	Solution s1;
	bool result = s1.wordBreak(s, wordDict);
	cout << result << endl;
	system("pause");
 	return 0;
}

end

相关推荐
倒头就睡的小比特2 天前
算法竞赛C++常用的STL
c++·算法
小羊没烦恼!2 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
猎头南楼2 天前
知识社区推荐系统实践:新用户冷启动与长短期兴趣建模的挑战 资深推荐算法工程师
人工智能·深度学习·算法·机器学习
旖旎夜光2 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
wzdark2 天前
大规模并行计算中的负载均衡算法研究4
算法
Because_of_Her12 天前
并查集-听课笔记
笔记·算法·并查集
码流子2 天前
高速公路安全监测实践:碰撞监测预警+物联网底座,从感知到处置的闭环
大数据·人工智能·物联网·算法·架构
another heaven2 天前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法
wzdark2 天前
从算法设计模式看编程思维的抽象能力4
算法
2601_962218612 天前
万象生鲜系统称重自动多退少补算法解决生鲜非标品痛点
大数据·数据库·人工智能·python·算法