Lintcode--009(单词切分)

http://www.lintcode.com/zh-cn/problem/word-break/

单词切分

给出一个字符串s和一个词典,判断字符串s是否可以被空格切分成一个或多个出现在字典中的单词。

样例

给出

s = "lintcode"

dict = ["lint","code"]

返回 true 因为"lintcode"可以被空格切分成"lint code"

标签:动态规划

解题:

题目理解:字典中的词是一个set,只要所给字符串可以被字典中给的词拼接出来,则表示可以切分。字典中的词语可以被重复使用;

例如:

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

 

 

还是动态规划问题, 动态规划的本质:根据已知结论推理未知结论。

思路: s = lintcode 可以分为 l和intcode,若是l是可分割单词,并且intcode单词在dict中,则表示s也是可分割单词。
若不符合,s = lintcode 可以分为 li和ntcode,若是li是可分割单词,并且ntcode单词在dict中,则表示s也是可分割单词。
...
同理得出BWord[ n ]表示字符串S[0,n]是否是可分割单词,是则为true,否为false。
BWord[ n ]  = BWord[ i ] &&( S[ i+1 ,n ]在dict中 )
 

C++代码:

class Solution { 
public: 
    /** 
     * @param s: A string s 
     * @param dict: A dictionary of words dict 
     */ 
    bool wordBreak(string s, unordered_set<string> &dict) { 
        // write your code here 
        //还是动态规划问题,先理解清楚题意; 
        //将问题转化为小规模的问题,先看子问题是不是,然后在扩展; 
        //程序思路很清楚; 
         
        int slen=s.size(); 
        int dlen=dict.size(); 
         
        if(slen==0&&dlen==0){ 
            return true; 
        } 
        if(slen==0||dlen==0){ 
            return false; 
        } 
        bool* dp=new bool[slen+1]; 
         
        dp[0]=true; 
        for(int i=0;i<slen;i++){ 
            if(!dp[i]){ 
                continue;//若dp[i]为false,则执行下一个i; 
            } 
            unordered_set<string>::iterator it; 
            for(it=dict.begin();it!=dict.end();++it){ 
                string value=*it; 
                int lv=value.size();//求出字典中字符串的长度; 
                if(i+lv>slen){ 
                    continue;//如果长度大于s,则执行字典中的下一个字符串; 
                } 
                string last=s.substr(i,lv); //以i为初始地址,偏移量为lv
                if(last==value){ 
                    dp[i+lv]=true; 
                } 
            } 
             
        } 
        return dp[slen]; 
    } 
};

 

 

官方标准解法:

class Solution {
public:
    /**
     * @param s: A string
     * @param wordSet: A dictionary of words dict
     * @return: A boolean
     */
    bool wordBreak(string &s, unordered_set<string> &wordSet) {
        // write your code here
        int len=s.size();
        vector<bool> flag(len+1,false);
        flag[0] = true;
        
        for(int i=1;i<len+1;i++){
            for(int j=i-1;j>=0;j--){
                if(flag[j]&&wordSet.count(s.substr(j,i-j))!=0){
                    flag[i]=true;
                    break;
                }
            }
        }

        return flag[len];
        
    }
};

  

注意,在使用递归方法解题时,如果需要存储中间结果,要定义一个全局变量实现,否则会有问题;

 

注:str.substr(startpos, length);

  其中 startpos 是起始字符的序号,length 是[从 startpos 开始]取的字符串长度(包括startpos )

 

# include<iostream>
# include<vector>
# include<string>
#include <algorithm>
# include<unordered_set>
using namespace std;

bool wordBreak(string &s, unordered_set<string> &wordSet) {
        // write your code here
        int len=s.size();
        vector<bool> flag(len+1,false);
        flag[0] = true;
         
        for(int i=1;i<len+1;i++){
            for(int j=i-1;j>=0;j--){
                if(flag[j]&&wordSet.count(s.substr(j,i-j))!=0){
                    flag[i]=true;
                    break;
                }
            }
        }
        return flag[len];
         
}

bool match(vector<string>& word_dict, string& str){
    int len = str.size();
    vector<bool> dp(len+1,false);

    dp[0]=true;
    
    for(int i=1;i<len+1;i++){
        for(int j=i-1;j>=0;j--){
            if(dp[j]&&(find(word_dict.begin(),word_dict.end(),str.substr(j,i-j))!=word_dict.end())){
                dp[i]=true;
                break;
            }
        }
    }
    return dp[len];
}

int main(){
    vector<string> word_dict = {"didi","xing","chu"};
    unordered_set<string> word = {"didi","chu","xing"};


    string  target = "didichuxing";
    // bool res = wordBreak(target,word);
    
    bool res=match(word_dict,target);
    cout<<res<<endl;

    return 0;

}

  

 

 

 

 

单词拆分III

 

样例
样例1

 

输入:
"CatMat"
["Cat", "Mat", "Ca", "tM", "at", "C", "Dog", "og", "Do"]
输出: 3
解释:
我们可以有如下三种方式:
"CatMat" = "Cat" + "Mat"
"CatMat" = "Ca" + "tM" + "at"
"CatMat" = "C" + "at" + "Mat"
样例2

 

输入:
"a"
[]
输出: 0

 

 

//递归方式:题目要求忽略大小写,所以要100%AC需要,将字符串提前都转换成小写

 

 

#ifndef C683_H
#define C683_H
#include<iostream>
#include<unordered_set>
#include<string>
using namespace std;
class Solution {
public:
    /*
     * @param : A string
     * @param : A set of word
     * @return: the number of possible sentences.
     */
    int wordBreak3(string& s, unordered_set<string>& dict) {
        // Write your code here
        if (s.empty() || dict.empty())
            return 0;
        int num = 0;
        helper(s, dict, 0, num);
        return num;
    }

    
    //pos表示字符串的当前位置,num表示可以组成语句的个数
    void helper(string &s, unordered_set<string>& dict, int pos,int &num)
    {
        if (pos == s.size())//已经遍历完字符串,num++
        {
            num++;
            return;
        }
        string str;
        //从当前位置向后取字符串,若存在于set中,改变pos的值,深度搜索
        for (int j = 1; j <= s.size() - pos; ++j)
        {
            str = s.substr(pos, j);
            if (dict.find(str) != dict.end())
            {
                helper(s, dict, pos + j, num);
            }
        }
    }
};
#endif

  

 

 

 

 

posted @ 2016-08-29 20:51  静悟生慧  阅读(961)  评论(0编辑  收藏  举报