Leetcode139题Word Break的两种动态规划解法

由leetcode139题Word Break产生的对动态规划的一点思考。

题目要求是这样的:

Given a string s and a dictionary of words dict,determine if s can be segmented into a space-separatedsequence of one or more dictionary words.

For example, given

s = "leetcode",

dict = ["leet", "code"].

Return true because "leetcode" can be segmented as "leet code".

HideTags

DynamicProgramming

大意是给定一个字符串和一个字典,问该字符串是否在字典中,或由字典中的单词拼接而成。

我的动态规划的版本:

bool wordBreak(string s, unordered_set<string> &dict)
{
	int length = s.size();
	vector<vector<bool>> f(length, vector<bool>(length));//f[i][j]表示从s中从下标i起j+1个字符能否被组合
	for (int j = 0; j < length; j++)//竖着,一列一列赋值
	{
		for (int i = 0; i <= length - j-1; i++)
		{
			bool flag = false;
			if (dict.count(s.substr(i, j + 1)) > 0)//截取字符串
				flag = true;
			for (int k = 1; k <= j&&!flag; k++)//能否组合出f[i][j]表示的子串,k表示组合中前半段的
				flag = f[i][k-1] && f[i + k][j - k];
			f[i][j] = flag;
		}
	}
	return f[0][length-1];
}

其中f[i][j]表示从s中从下标i起j+1个字符能否被组合

具体思路就是:

f[i][j]作为一整段位于字典中 或 f[i][j]可以分两段分别能被组合而成

二维数组从左往右从上往下依次被填充。

提交之后发现较平均水准稍慢一点点,网上搜了一下发现第二种动态规划的写法

bool wordBreak(string s, unordered_set<string> &dict)
{
	int n = (int)s.size();
	vector<bool> dp(n + 1, false);
	dp[0] = true;
	for (int i = 0; i < n; i++)
	{
		if (dp[i])
		{
			for (int len = 1; i + len - 1 < n; len++)
				if (dict.count(s.substr(i, len)) > 0)
					dp[i + len] = true;
		}
	}
	return dp[n];
}

仔细对比了一下,发现解法一虽然没有重复计算,但有无用计算。解法二是比解法一更优的方案,没有无用计算。

解法一中,要判断f[i][j],必须知道每一个f[i][k-1]和f[i + k][j - k](其中1<=k<=j),所以将二维数组f想象成一个矩形,要填充一个格子,必须事先计算它左下方的所有格子(越界的格子当然不算)的值。

当所有格子都填充完毕后,解法一实际上已经求出了s的所有子串是否能由字典中的词组合而成。而题目只要求判断s,仔细分析,发现解法一存在无用计算:

对于字符串s,当它的前半段已经求出不能由字典中词组合而成时,就没必要对后半段进行检查了。因为s是确定唯一的,这种组合已经不可能构成s。若是不唯一的,则检查后半段可用于其他组合。

而解法二就利用了这一点,当且仅当前半段能组合而成,才对后面可能的组合进行检查,避免了无用计算。

时间: 2024-10-29 19:08:51

Leetcode139题Word Break的两种动态规划解法的相关文章

华为机试—N皇后问题(高级题160分:两种回溯法解决 吐血整理)

一.问题描述: 在n×n格的棋盘上放置彼此不受攻击的n个皇后.按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子.n后问题等价于再n×n的棋盘上放置n个皇后,任何2个皇后不妨在同一行或同一列或同一斜线上. 输入: 给定棋盘的大小n (n ≤ 13) 输出: 输出有多少种放置方法. 二.解题思路: 要解决N皇后问题,其实就是要解决好怎么放置这n个皇后,每一个皇后与前面的所有皇后不能在同一行.同一列.同一对角线,在这里我们可以以行优先,就是说皇后的行号按顺序递增,只考虑第i个皇

LeetCode: Word Break II 解题报告

Word Break II Given a string s and a dictionary of words dict, add spaces in s to construct a sentence where each word is a valid dictionary word. Return all such possible sentences. For example, given s = "catsanddog", dict = ["cat",

第九章 两种模式的比较

#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <assert.h> #include <stdio.h> #include <unistd.h> #include <errno.h> #include <string.h> #include

QT中获取选中的radioButton的两种方法(动态取得控件的objectName之后,对名字进行比较)

QT中获取选中的radioButton的两种方法 QT中要获取radioButton组中被选中的那个按钮,可以采用两种如下两种办法进行: 方法一:采用对象名称进行获取 代码: 1 QRadioButton* pbtn = qobject_cast<QRadioButton*>(ui->BG->checkedButton()); 2 QString name = pbtn->objectName(); 3 if(!QString::compare(name, "rad

QT中获取选中的radioButton的两种方法

QT中要获取radioButton组中被选中的那个按钮,可以采用两种如下两种办法进行: 方法一:采用对象名称进行获取 代码: 1 QRadioButton* pbtn = qobject_cast<QRadioButton*>(ui->BG->checkedButton()); 2 QString name = pbtn->objectName(); 3 if(!QString::compare(name, "radioButton")) 4 { 5 QM

【LeetCode每天一题】Word Break()

Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if s can be segmented into a space-separated sequence of one or more dictionary words. Note: The same word in the dictionary may be reused multiple t

涨姿势题2_水题_两种解法

Problem Description 涨姿势题就是所谓的优化题,在组队赛中,队伍发现了一题水题,那么应该交给谁去处理?作为处理水题的代码手,应该具备什么样的素养?1,要快,水题拼的就是速度!2,不能卡水题!水题都卡,绝对不是一个代码手的风范!3,不能出错,错一次即罚时20分钟,对于水题来讲是致命的!4,要能看出来一题是水题!没有这条,上面三条都是没有意义的! 如果你希望你成团队中一个合格的代码手,那么这套题是你最好的选择,快AC吧! 本系列即是为了提高水题代码手的素养而准备的!水题经常需要用到

【动态规划】01背包问题_两种解法

问题描述 0-1背包问题:给定\(n\)种物品和一背包.物品i的重量是\(w_i\),其价值为\(v_i\),背包的容量为\(C\).问:应该如何选择装入背包的物品,使得装人背包中物品的总价值最大? 在选择装人背包的物品时,对每种物品\(i\)只有两种选择,即装人背包或不装入背包.不能将物品\(i\)装入背包多次,也不能只装入部分的物品\(i\).因此,该问题称为0-1背包问题. 此问题的形式化描述是,给定\(C>0\),\(w_i>0\),\(v_i>0\),\(1≤i≤n\),要求找

ZOJ3822 ACM-ICPC 2014 亚洲区域赛牡丹江赛区现场赛D题Domination 概率DP(两种解法)

题目地址:点击打开链接 这道题有两种做法,第一种是直接求期望,类似于poj 2096 区别在于这个步数有限.所以要迭代步数. #include <cstdio> #include <cstring> #include <iostream> #define maxn 55//这里刚开始写成了50+10 那么maxn*maxn就会小很多wa了一次 using namespace std; double dp[maxn][maxn][maxn*maxn]; int N,M,T