Leetcode 139. WordBreak 解法和思路

栏目: 编程工具 · 发布时间: 7年前

内容简介:原文的题干如下:Given a大致意思是给定一个非空字符串

原文的题干如下:

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.

大致意思是给定一个非空字符串 s ,和一个词典 wordDict ,词典包含一系列的词。需要找出的是这个字符串s可否完全用词典中的词分隔成单个单词。

例子

输入: s = "leetcode", wordDict = ["leet", "code"]
输出: true
说明:leetcode -> leet code
复制代码
输入: s = "applepenapple", wordDict = ["apple", "pen"]
输出: true
说明:applepenapple -> apple pen apple
复制代码
输入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
输出: false
说明: catsandog中的cat sand和dog互相有重叠,无法区隔
复制代码

2 错误的解法

最开始没有细想,用了比较暴力的解法,

class Solution {
public:
	string reduce(string s, vector<string>& wordDict) {
		for (vector<string>::iterator iter = wordDict.begin(); iter != wordDict.end(); ++iter) {
			size_t pos = s.find(*iter);
			if (pos != string::npos) {
				string left = s.substr(0, pos);
				string right = s.substr(pos + (*iter).size());
				if (evaluate(left, right, wordDict) == "OK") {
					return "";
				}
			}
		}
		return s;
	}

	string evaluate(string left, string right, vector<string>& wordDict) {
		if (reduce(left, wordDict).size() == 0 && reduce(right, wordDict).size() == 0) {
			return "OK";
		}
		return "BAD";
	}
	
	bool wordBreak(string s, vector<string>& wordDict) {
		string result = reduce(s, wordDict);
		if (result == "") {
			return true;
		}
		return false;
	}
};
复制代码

之所以想到这个解法,主要是因为第一联想到的是编译原理中的语法分析。有一些文法使用一种称为 递归下降 (recursive descent)的简单算法就很容易进行分析。这种算法的实质是将每一个文法产生式转变成递归函数的一个子句 [1] 。简单来说就是把所有可能性表示成一棵树,在单词不能再分割的时候,使之成为叶子节点,然后依次回溯求值,最终得到最开始的字符串是否是可分割的。

这道题一共有36个Test Case,我的代码执行到第30个用例的时候就会开始Time Exceeded了,原因很明显:在极端的用例情况,树的分支太多太深,遍历全部路径会花费很长时间。

3 动态规划解法

因此回到最开始,这道题的良解之一是 动态规划 (DP,Dynamic Programming)。

动态规划是一种算法设计技术,该技术认为最优化问题的任一实例的最优解,都是由其子实例的最优解构成的 [2] 。文字描述起来比较难懂,下面就这个问题举例说明:

输入: s = "ccaccc", wordDict = ["cc", "ac"]
输出: true
说明:ccaccc -> cc ac cc
复制代码

按照动态规划的常见思路,我们一般会把目标集合划分为下标从0到最大值不断迭代的对象。通常我们需要一个初始值F(0),这里虽然题干规定s一定不为空,但这里我们可以令F(0)=True,也就是没有任何字符串的时候,输出可以为True。然后依次递增下标,每次递增都从当前下标遍历词典中的词,只要当前下标的位置可以找到词典中的词,并且当前下标之前也是一个可分对象,就可以认为找到的这个词典的词,以及下标之前的部分,是本题的解之一。

下标 0 1 2 3 4 5 6
字符 c c a c c c
标记 1 1 1 1

下面用代码表述一下这个解法:

class Solution {
public:	
	bool wordBreak(string s, vector<string>& wordDict) {
		size_t n = s.size();
		vector<int> dp(n+1, 0);
		dp[0] = 1;
		for (size_t i = 0; i < n; ++i) {
			for (vector<string>::iterator iter = wordDict.begin(); iter != wordDict.end(); ++iter) {
				if(s.substr(i).find(*iter)==0 && dp[i]) {
					dp[i + (*iter).size()] = 1;
				}
			}
		}
		return bool(dp[n]);
	}
};
复制代码

可以发现该解法已经属于较良好解法。

Leetcode 139. WordBreak 解法和思路

当然,可以看到前方仍然有12%的Runtime,因此应该还存在改进空间,大家刷到这题的时候也可以自己再多方面尝试一下。


以上所述就是小编给大家介绍的《Leetcode 139. WordBreak 解法和思路》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

探索需求

探索需求

章柏幸、王媛媛、谢攀、杰拉尔德・温伯格、唐纳德・高斯 / 章柏幸、王媛媛、谢攀 / 清华大学出版社 / 2004-7-1 / 39.00元

本书将与您一起寻找"什么是客户真正想要的"这一问题的答案。 本书着眼于系统设计之前的需求过程,它是整个开发过程(如何设计人们想要的产品和系统)中最有挑战性的那部分。通过对一些需求分析中的常见误区和问题的分析和讨论,从和客户沟通开始,深入研究一些可能的需求,澄清用户和开发者期望值,最终给出了能够大幅度提高项目成功几率的一些建议方法。 本书由该领域内公认的两位作者合著,搜集了他们在大大小小......一起来看看 《探索需求》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具