zoukankan      html  css  js  c++  java
  • 【LeetCode & 剑指offer刷题】动态规划与贪婪法题15:Word Break(系列)

    【LeetCode & 剑指offer 刷题笔记】目录(持续更新中...)

    Word Break(系列)

    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 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

    C++
     
    /*
    问题:拆分词句,看给定的词句能分被拆分成字典里面的内容
    方法:动态规划
    f[i]表示s[0,i-1]是否可以被分词,表示在第i个字符后面的隔板
    状态转移方程:f(i) = any_of(f(j)&&s[j,i-1] ∈ dict); j = 0~i-1
    例:
    Input: s = "leetcode", wordDict = ["leet", "code"]
    f[0] = true
    i=1,j=0: l
    i=2,j=0: le
        j=1: e
    i=3,j=0: lee
        j=1: ee
        j=2: e
    i=4,j=0: leet  f[4] = true
        j=1: eet
        j=2: et
        j=3: t
    ...
    O(n^2)
    假设总共有n个字符串,并且字典是用HashSet来维护,那么总共需要n次迭代,每次迭代需要一个取子串的O(i)操作,然后检测i个子串,而检测是constant操作。所以总的时间复杂度是O(n^2)(i的累加仍然是n^2量级),而空间复杂度则是字符串的数量,即O(n)(本题还需加上字典的空间)
    */
    class Solution
    {
    public:
        bool wordBreak(string s, vector<string> &wordDict)
        {
            unordered_set<string> new_dict(wordDict.begin(), wordDict.end());//转化为哈希表,方便查找
           
            //长度为n的字符串有n+1个隔板,多分配一个空间以方便后续递推
            vector<bool> f(s.size() + 1, false);
           
            f[0] = true; // 空字符串,初始化为true,以便后续迭代
            for (int i = 1; i < f.size(); i++) //以s[i-1]字符结尾的子串, i=1~n
            {
                for (int j = 0; j < i; j++) //以s[j]开头的子串,j=0~i-1
                {
                    if (f[j] && new_dict.find(s.substr(j, i-j)) != new_dict.end())//substr[start,len)
                    {
                        f[i] = true;
                        break;
                    }
                }
            }
            return f[s.size()];
        }
    };
     
    Word Break II
    Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, add spaces in s to construct a sentence where each word is a valid dictionary word. Return all such possible sentences.
    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 = "catsanddog"
    wordDict = ["cat", "cats", "and", "sand", "dog"]
    Output:
    [
    "cats and dog",
    "cat sand dog"
    ]
    Example 2:
    Input:
    s = "pineapplepenapple"
    wordDict = ["apple", "pen", "applepen", "pine", "pineapple"]
    Output:
    [
    "pine apple pen apple",
    "pineapple pen apple",
    "pine applepen apple"
    ]
    Explanation: Note that you are allowed to reuse a dictionary word.
    Example 3:
    Input:
    s = "catsandog"
    wordDict = ["cats", "dog", "sand", "and", "cat"]
    Output:
    []

    C++
     
    /*
    问题:拆分词句2,返回所有分隔结果
    方法:dfs
    联系排列组合问题
    这里用一个hash表避免对相同子串s进行重复分隔,减少重复计算
    */
    class Solution {
    public:
        vector<string> wordBreak(string s, vector<string>& wordDict)
        {
            unordered_map<string, vector<string>> m;
            return dfs(s, wordDict, m);
        }
        vector<string> dfs(string s, vector<string>& wordDict, unordered_map<string, vector<string>>& m)
        {
            if (m.find(s) != m.end()) return m[s]; //如果对s的分隔已经递归过了,就直接退出
            if (s.empty()) return {""}; //map型数据类型用{},递归的出口
           
            vector<string> res; //某一次的分隔结果
            for (string word : wordDict) //遍历字典中的单词(递归的分支)
            {
                if (word == s.substr(0, word.size()) )//如果当前单词在s开头
                {
                    //substr 返回子串 [pos, pos+count) 。若请求的子串越过 string 的结尾,或若 count == npos ,则返回的子串为 [pos, size())
                    vector<string> rem = dfs(s.substr(word.size()), wordDict, m); //对该单词后面的子串递归(分支的深度),返回后面子串的分隔结果
                   
                    for (string str : rem) //拼接后面子串的分隔结果与当前单词
                    {
                        res.push_back(word + (str.empty() ? "" : " ") + str); //将word和str push到结果向量中,中间用空格隔开,此为某一种结果
                    }               
                }
               
            }
           
            return m[s] = res; //返回对s的分隔结果
        }
    };
     
  • 相关阅读:
    OSCP Learning Notes Buffer Overflows(3)
    OSCP Learning Notes Buffer Overflows(5)
    OSCP Learning Notes Exploit(3)
    OSCP Learning Notes Exploit(4)
    OSCP Learning Notes Exploit(1)
    OSCP Learning Notes Netcat
    OSCP Learning Notes Buffer Overflows(4)
    OSCP Learning Notes Buffer Overflows(1)
    OSCP Learning Notes Exploit(2)
    C++格式化输出 Learner
  • 原文地址:https://www.cnblogs.com/wikiwen/p/10229397.html
Copyright © 2011-2022 走看看