【字符串】单词拆分

题目:

解答:

说实话,我自己是没有想出来这道题要用到动态规划的思想,而且一开始也没有理解这种方法。

具体方法:

(1)本题的子问题设为从字符串 s 的前 i 个元素中能否切分出字典 wordDict 里面的单词。因为考虑到空字符串的问题,我们将用于记录子问题信息的vector定义为 len+1 大小。我们认为空字符也包含在了字典中,所以空字符串对应的isWordBreak[0] = true。

(2)为了方便查找某一段字符串是否在字典中,先将字典中的元素保存到一个set类型中。

(3)用一个双循环进行判断。每次判断的是 i 前面的元素。每次判断第 j 个元素到第 i -1个元素是否在字典中。一开始isWordBreak[0]=true,第一个判断语句不起作用,所以是从字符串的第一个元素开始截取字符串判断,一直到找到从字符串第一个元素开始的一段字符串是属于字典中的为止,此时将这个位置 i 的信息记为 true 。

之后的循环,通过程序中第一个判断语句实现每次都从已经找到的字符串的下一个位置开始截取(因为这个题目中,字符串 s 不允许有剩余,所以要这样做)。最后一次判断的是从某一位置一直到末尾的最后一段字符串是否在字典中。

如果最后这一段也在字典中,那么就说明可以实现,否则不可以。

(4)给一个特例,希望有助于理解:

如果字符串从第一元素开始,一直到字符串末尾都不可以截取属于字典中的单次,那么程序外层循环将一直执行到 i = len,isWordBreak[len]=false.那么就直接返回 false。

这段程序的思想:(理解的关键)

从第一元素开始寻找属于字典中的单词,之后在从这个单词的后一个位置继续寻找,如果一直到末尾都是属于字典的,那么就返回true,否则返回false。

class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict) 
    {
        int len = s.size();
        
        // 定义一个含有len+1个元素的vector,用于存储子问题信息
        vector<bool> isWordBreak(len + 1, false);
        
        // 将第一个元素设置为true,表示当字符串为空的时候也成立
        isWordBreak[0] = true;
        
        std::set<string> dict;
        
        for(const auto &ss:wordDict) 
        {
            dict.insert(ss);
        }
        
        for(int i = 0;i < len + 1; ++i)
        {
            for(int j = 0;j < i; ++j)
            {
                // 本条语句用于控制,每次都从上一次找到的元素的下一个位置开始截取字符串
                if(!isWordBreak[j])
                {
                    continue;
                }
                // 从位置j开始,截取i-j长度的字符串,如果没有找到,那么将返回最后一个元素的后一个位置的迭代器
                if(dict.find(s.substr(j,i-j)) != dict.end())
                {
                    isWordBreak[i]=true;
                    break;
                }
            }
        }
        return isWordBreak[len];
    }
};

猜你喜欢

转载自www.cnblogs.com/ocpc/p/12900037.html