【leetcode】140 单词拆分II(字符串,回溯)

题目链接:https://leetcode-cn.com/problems/word-break-ii/

题目描述

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

说明:

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

示例 1:

输入:
s = "catsanddog"
wordDict = ["cat", "cats", "and", "sand", "dog"]
输出:
[
  "cats and dog",
  "cat sand dog"
]

示例 2:

输入:
s = "pineapplepenapple"
wordDict = ["apple", "pen", "applepen", "pine", "pineapple"]
输出:
[
  "pine apple pen apple",
  "pineapple pen apple",
  "pine applepen apple"
]
解释: 注意你可以重复使用字典中的单词。

示例 3:

输入:
s = "catsandog"
wordDict = ["cats", "dog", "sand", "and", "cat"]
输出:
[]

思路

求组合的题目,采用回溯思想解决。
对于当前待匹配字符串s,拆解为如下步骤:
(1)遍历词典,找到能匹配s的词典的词word
(2)对于s减去word后的子串,递归得到其组合res
(3)在res中的每个字符串前加入word

上述步骤的核心在于,通过回溯,将字符串头部匹配的词顺利地加入到子串的组合前;

注意:
这里采用遍历词典的方式,目的是对于同一个字符串s,能够找到不同的词的组合方式,且避免重复计算。
该方法通过遍历词组而不是遍历字符串s的每个字符,时间开销小;
但是对于每个子串组合都要得到一份组合列表,vector<string> res = wordBreakCore(s.substr(word.size()), wordDict, m); 引入一定的空间开销。
此外,为了避免重复计算,利用unordered_map存储一个映射表,对于已有的字符串组合,直接查表得到。

代码

class Solution {
public:
    vector<string> wordBreak(string s, vector<string>& wordDict) {
        unordered_map<string,vector<string>> m;
        vector<string> ret;
        ret = wordBreakCore(s,wordDict,m);
        return ret;
    }


    // 得到字符串s的字典拆分组合
    vector<string> wordBreakCore(string s, vector<string>& wordDict, unordered_map<string,vector<string>> &m){
        if(m.count(s)) return m[s];     // 如果字典里有直接返回已有组合
        if(s.empty()) return {""};      // 返回空串

        vector<string> result;
        // 匹配词典
        for (string word:wordDict) {
            if(s.substr(0,word.size()) == word){
                vector<string> res = wordBreakCore(s.substr(word.size()), wordDict, m);
                for(string str:res){
                    // res列表里每个字符串前加入word +  " "
                    result.push_back(word + (str.empty()?"": " "+ str));
                }
            }
        }
        m[s] = result;
        return result;
    }
};

猜你喜欢

转载自blog.csdn.net/zjwreal/article/details/89409676