Leetcode 139&140. Word Break I & II

139. 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. You may assume the dictionary does not contain duplicate words.

For example, given

s = "leetcode",
dict = ["leet", "code"].

Return true because"leetcode" can be segmented as "leet code".

题目解析

这题是求解能否分解成字典里的字符串,即是否问题,找到一个符合的即可。因此我们就开始搜索,想到了之前的回文串动态规划的表达式:f[n] = (f[i],s[i~n]) && f[i]=true。即,对于每个f[n]表示能否到达这个位置,遍历前面的位置,如果能到达前面的第i个位置,那我们就看看字典里是否有s[i~n]这个字符串,如果有,我们就可以通过这个字符到达当前字符,就可以确认可以到达i位置了,就不需要继续搜这个位置了。往下搜,能到最后一个位置说明能够分解。

代码

class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        unordered_set<string> ss;
        for (auto &i : wordDict)
            ss.insert(i);
        vector<bool> f(s.size()+1, false);
        f[0] = true;
        for (int i = 1; i <= s.size(); ++i)
        {
            for (int j = 0; j < i; ++j)
            {
                if (f[j])
                {
                    string subs = s.substr(j, i - j);
                    if (ss.count(subs))
                    {
                        f[i] = true;
                        break;
                    }
                }           
            }
        }
        return f[s.size()];
    }
};

140. 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. You may assume the dictionary does not contain duplicate words.
Return all such possible sentences.
For example, given

s = "catsanddog",
dict = ["cat", "cats", "and", "sand", "dog"].

A solution is ["cats and dog", "cat sand dog"].

题目解析

看到这个题目,发应过来又是一个深度搜索的问题,构建字符串。好吧,我们开始搜吧。

想法一

这是最直观的深度优先搜索,从起点出发,如果存在字典中字符串,移动一步,然后递归构造结果。over,果不其然超时了,卡在第29个测试用例上,人家可是hard类型的题目,这么简单的被做出来岂不是很没面子,继续想吧。

代码如下:

class Solution {
public:
    void solve(unordered_set<string> &ss,int idx,string s,vector<string> &vs,vector<string> &data)
    {
        if (idx == s.size())
        {
            string str;
            for (int i = 0; i < data.size() - 1; i++)
            {
                str += data[i];
                str += " ";
            }
            str += data[data.size() - 1];
            vs.push_back(str);
            return;
        }
        for (int i = idx; i < s.size(); ++i)
        {
            string tmp = s.substr(idx, i - idx + 1);
            if (ss.count(tmp))
            {
                data.push_back(tmp);
                solve(ss,i+1,s, vs, data);
                data.pop_back();
            }
        }
    }

    vector<string> wordBreak(string s, vector<string>& wordDict) {
        unordered_set<string> ss;
        for (auto &i : wordDict)
            ss.insert(i);
        vector<string> vs;
        vector<string> data;
        solve(ss, 0, s, vs, data);
        return vs;
    }
};

想法二

首先我们是不是递归的时候,遍历的太多,因为很多子串是不存在字典中,因此遍历是无效的。因此,我就想,我给每个位置所可能的后续点生成一个vector,每个位置只需要遍历这个数组就可以了,但是这个题目还是很顽强啊,还是超时==可能是生成这个vector花的时间更多吧。
代码如下:

class Solution {
public:
    void solve( unordered_map<int, vector<int>> &mii,int idx, string s, vector<string> &vs, vector<string> &data)
    {
        if (idx == s.size())
        {
            string str;
            for (int i = 0; i < data.size() - 1; i++)
            {
                str += data[i];
                str += " ";
            }
            str += data[data.size() - 1];
            vs.push_back(str);
            return;
        }
        vector<int> d = mii[idx];
        for (auto &i:d)
        {
            string tmp = s.substr(idx, i - idx + 1);
            data.push_back(tmp);
            solve(mii,i + 1, s, vs, data);
            data.pop_back();
        }
    }

    vector<string> wordBreak(string s, vector<string>& wordDict) {
        vector<string> vs;
        vector<string> data;
        unordered_set<string> ss;
        for (auto &i : wordDict)
            ss.insert(i);
        vector<bool> f(s.size() + 1, false);
        unordered_map<int, vector<int>> mii;
        f[0] = true;
        for (int i = 1; i <= s.size(); ++i)
        {
            for (int j = 0; j < i; ++j)
            {
                if (f[j])
                {
                    string subs = s.substr(j, i - j);
                    if (ss.count(subs))
                    {
                        f[i] = true;
                        mii[j].push_back(i - 1);                       
                    }
                }
            }
        }
        solve(mii,0, s, vs, data);
        return vs;
    }
};

想法三

哎,很丧气啊,怎么办,不会了。到底是哪里有重复计算了,想破脑壳,想起来前面的看能分解,只需要一个分解就可以了,那反过来,如果一个位置搜索不到结尾,那是不是以后到这个位置就直接不搜索了。对啊,这不就是备忘录方法吗!!!瞧这记性,做完上题忘下题。因此我们使用一个数组来记录每个地方能否到达结尾,一旦到达不了,做一个标记,下次搜到这个位置就不搜索了,好像是减少了不少。
代码如下:

class Solution {
public:
    bool solve(unordered_set<string> &ss, int idx, string s, vector<string> &vs, vector<string> &data, vector<bool> &f)
    {
        if (idx == s.size())
        {
            string str;
            for (int i = 0; i < data.size() - 1; i++)
            {
                str += data[i];
                str += " ";
            }
            str += data[data.size() - 1];
            vs.push_back(str);
            return true;
        }
        if (f[idx] == false)
            return false;
        bool flag = false;
        for (int i = idx; i < s.size(); ++i)
        {
            string tmp = s.substr(idx, i - idx + 1);
            if (ss.count(tmp))
            {           
                data.push_back(tmp);
                // 这里注意,要把solve写前面,因为或运算第一个是true就不算后面的
                flag = solve(ss, i + 1, s, vs, data, f) || flag;
                data.pop_back();
            }
        }
        f[idx] = flag;  
        return flag;
    }

    vector<string> wordBreak(string s, vector<string>& wordDict) {
        unordered_set<string> ss;
        for (auto &i : wordDict)
        {
            ss.insert(i);
        }       
        vector<string> vs;
        vector<string> data;
        vector<bool> f(s.size(), true);
        solve(ss, 0, s, vs, data,f);
        return vs;
    }
};

欢迎指正。

猜你喜欢

转载自blog.csdn.net/hu694028833/article/details/79166783
今日推荐