LeetCode单词拆分——动态规划

LeetCode单词拆分——动态规划

  • 前言
  • LeetCode #139 单词拆分
  • LeetCode #140 单词划分II

前言

字符串的问题很多都是动态规划解决的,LeetCode #139 单词拆分、#140 单词拆分II 是典型运用动态规划的两道题。

LeetCode #139 单词拆分

题目描述

给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。

说明:

  • 拆分时可以重复使用字典中的单词。
  • 你可以假设字典中没有重复的单词。

算法思路

s 是有限字母组成的字符串,是否全部可分取决于两个因素:

  1. 子串是否在字典中
  2. 可分子串的前一个子串是否可分

第二个因素决定了这道题可以划分为一系列小问题,这是典型的动态规划问题。

代码实现

class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        set<string> st(wordDict.begin(), wordDict.end());
        vector<bool> dp(s.size() + 1, false);
        dp[0] = true;
        for (int i = 1; i <= s.size(); ++i) {
            for (int j = 0; j < i; ++j) {
                if (dp[j] && st.find(s.substr(j, i - j)) != st.end()) {
                    dp[i] = true;
                    break;
                }
            }
        }
        return dp[s.size()];
    }
};

LeetCode #140 单词划分II

题目描述

给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,在字符串中增加空格来构建一个句子,使得句子中所有的单词都在词典中。返回所有这些可能的句子。

说明:

  • 分隔时可以重复使用字典中的单词。
  • 你可以假设字典中没有重复的单词。

算法思路

#140 是 #139 的延续,这里不仅仅要求字符串可以完全划分,也需要重新组合成新的字符串。我们依据上一题的思路,重新规划动态规划数组。 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示 j − i j-i ji 之间的子串在字典中,且 i i i 之前的子串可以完全划分。

之后,在构造句子上,我们采用 unordered_map 数据结构。key 为字符串下标,value 为当前位置前可能组成的句子。

代码实现

class Solution {
public:
	vector<string> wordBreak(string s, vector<string>& wordDict) {
		int len = s.size();
		set<string> st;
		int minLength = INT_MAX, maxLength = 0;
		for (const string& word : wordDict) {
			if (word.size() < minLength) minLength = word.size();
			if (word.size() > maxLength) maxLength = word.size();
			st.insert(word);
		}
		vector<vector<int>> dp(len + 1);
		dp[0] = {0};
		for (int j = 1; j <= len; ++j) {
			for (int i = max(0, j - maxLength); i <= j - minLength; ++i) {
				if (!dp[i].empty() && st.count(s.substr(i, j - i)) {
					dp[j].push_back(i);
				}
			}
		}
		if (dp[len].empty()) return vector<string>();
		unordered_map<int, vector<string>> m;
		for (int j = 1; j <= len; ++j) {
			if (dp[j].empty()) continue;
			for (const int& i : dp[j]) {
				if (m.find(i) == m.end()) {
					m[j].push_back(s.substr(i, j - i));
				} else {
					for (const string& ss : m[i]) {
						m[j].push_back(ss + ' ' + s.substr(i, j - i));
					}
				}
			}
		}
		return m[len];
	}
};

@北京·海淀 2019.12.17

你可能感兴趣的:(Leetcode,字符串,算法,数据结构,leetcode)