MENU

LeetCode139. Word Break(动态规划)

2019 年 04 月 10 日 • 阅读: 2073 • LeetCode阅读设置

LeetCode139. Word Break(动态规划)

  • Medium
  • Accepted:318,728
  • Submissions:915,955

Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if scan be segmented into a space-separated sequence of one or more dictionary words.

Note:

  • The same word in the dictionary may be reused multiple times in the segmentation.
  • You may assume the dictionary does not contain duplicate words.

Example 1:

Input: s = "leetcode", wordDict = ["leet", "code"]
Output: true
Explanation: Return true because "leetcode" can be segmented as "leet code".

Example 2:

Input: s = "applepenapple", wordDict = ["apple", "pen"]
Output: true
Explanation: Return true because "applepenapple" can be segmented as "apple pen apple".
             Note that you are allowed to reuse a dictionary word.

Example 3:

Input: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
Output: false

链接

https://leetcode.com/problems/word-break

题意

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

题解

之前做的题LeetCode322. Coin Change零钱凑整,这道题就是“单词凑字符串”。我们可以对字符串进行分割,看当前分割的字符串能否由字典列表中的单词凑成以及剩余部分是否在单词列表中。可以使用unordered_set保存列表单词。

两种方式,自顶向下的记忆化搜索递归和自底向上的动态规划。

对于动态规划,dp[i]表示s[0...i-1]是否能由字典列表中的单词凑成,如果子串s[0...j-1]可以被拆分,且s[j...i]在字典列表列表中,那么dp[i]为真。

$dp[i] = dp[j] \ \&\& \ dict.find(s.substr(j, i - j)), \ j < i​$。

时间复杂度:$O(n^2)$,n为字符串长度。

代码

  • Runtime: 44 ms, faster than 6.62% of C++ online submissions for Word Break.
  • Memory Usage: 22 MB, less than 5.16% of C++ online submissions for Word Break.
class Solution {
private:
    unordered_map<string, bool> memo;
    bool solve(string& s, unordered_set<string>& dict)
    {
        if (memo.find(s) != memo.end()) // 记忆化
            return memo[s];
        if (dict.find(s) != dict.end()) // s在dict中
            return memo[s] = true;
        for (int i = 1; i < s.length(); ++i)
        {
            string left = s.substr(0, i);
            string right = s.substr(i);
            // 左边能拼凑且右边在字典中
            if (solve(left, dict) && dict.find(right) != dict.end())
                return memo[s] = true;
        }
        return memo[s] = false; // 不能拼凑
    }

public:
    bool wordBreak(string s, vector<string>& wordDict) {
        unordered_set<string> dict(wordDict.begin(), wordDict.end());
        return solve(s, dict);
    }
};
  • Runtime: 16 ms, faster than 62.54% of C++ online submissions for Word Break.
  • Memory Usage: 14.3 MB, less than 54.46% of C++ online submissions for Word Break.
class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        unordered_set<string> dict(wordDict.begin(), wordDict.end());
        int n = s.length();
        vector <bool > dp(n + 1, false);
        dp[0] = true;
        for (int i = 1; i <= n; ++i)
        {
            for (int j = 0; j < i; ++j)
            {
                if (dp[j] && dict.find(s.substr(j, i - j)) != dict.end())
                {
                    dp[i] = true;
                    break;
                }
            }
        }
        return dp[n];
    }
};

参考


The end.
2019年4月10日 星期三