• [leetcode]Word Break


    先上自己的代码

     1 class Solution {
     2 public:
     3     bool wordBreak(string s, unordered_set<string> &dict) {
     4         vector<bool> dp(s.size()+1,false);//dp[i]表示从下标0开始的长度为i的子串能否满足word break;
     5         dp[0] = true;//相当于分割成了空串和完整的字符串s。不能让dp[0]成为&&判断的绊脚石(&&右边如果是个完整串且为真,不能让dp[0]给破坏了)
     6         for (int i = 1; i <= int(s.size()); i++)//i表示当前串的长度(DP自底向上,串的长度从1到n依次增大、记录数据。)
     7         {
     8             for (int k = 0; k < i; k++)//k的意义为将当前长度为i的大串分成左边长为k,右边长为i-k的两个字串。
     9                 //随着k的不同,将长为i的串以不同的左右比例依次切分看能否word break.
    10             {
    11                 if (dp[k] && dict.find(s.substr(k, i - k))!=dict.end())//下标不要搞错!substr第一个参数是k不是k+1。
    12                 {
    13                     dp[i] = true;
    14                     break;
    15                 }
    16             }
    17         }
    18         return dp[s.size()];
    19     }
    20 };

    ======================================================================================================================

    http://www.cnblogs.com/lautsie/p/3371354.html

    LeetCode越来越大姨妈了,Submit上去又卡住了,先假设通过了吧。这道题拿到思考先是递归,然后有重复子状态,显然是DP。用f(i,j)表示字符串S从i到j的子串是否可分割,则有:f(0,n) = f(0,i) && f(i,n)。
    但是如果自底向上求的话会计算很多不需要的,比如leet已经在字典里了,很多情况下就不需要计算下面的l,e,e,t了,所以自顶向下递归+备忘录会是更快的方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    import java.util.*;
    public class Solution {
        private int f[][] = null;
        public boolean wordBreak(String s, Set<String> dict) {
            int len = s.length();
            f = new int[len][len]; // 0 for unvisited, -1 for false, 1 for true
            return wordBreak(s, dict, 0, len-1);
        }
         
        private boolean wordBreak(String s, Set<String> dict, int i, int j) {
            if (f[i][j] == 1) return true;
            if (f[i][j] == -1) return false;
            String s0 = s.substring(i, j + 1);
            if (dict.contains(s0)) {
                f[i][j] = 1;
                return true;
            }
            for (int k = i + 1; k <= j; k++) {
                if (wordBreak(s, dict, i, k-1) && wordBreak(s, dict, k, j)) {
                    f[i][j] = 1;
                    return true;
                }
            }
            f[i][j] = -1;
            return false;
        }
    }

    但是如果自底向上,状态就可以滚动数组优化少一维表示,比如下面,用wordB[i]表示从0开始长度为i的子串是否能分割。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class Solution {
    public:
        bool wordBreak(string s, unordered_set<string> &dict) {
            vector<bool> wordB(s.length() + 1, false);
            wordB[0] = true;
            for (int i = 1; i < s.length() + 1; i++) {
                for (int j = i - 1; j >= 0; j--) {
                    if (wordB[j] && dict.find(s.substr(j, i - j)) != dict.end()) {
                        wordB[i] = true;
                        break;
                    }
                }
            }
            return wordB[s.length()];
        }
    };

    还有一种字典树的方法,很巧妙,用个vector<bool>记录了是否能从头经过word break走到位置 i。正好练练手写写Trie树试下。http://www.iteye.com/topic/1132188#2402159

    Trie树是Node且自身包含Node*的数组,如果数组某个位置不是NULL就代表此处有字符,end表示这里是一个字符串的终结。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    #include <string>
    #include <vector>
    #include <unordered_set>
    using namespace std;
     
    class Node {
    public:
        Node* next[26];
        bool end;
     
        Node() : end(false) {
            for (int i = 0; i < 26; i++) {
                next[i] = NULL;
            }
        }
        ~Node() {
            for (int i = 0; i < 26; i++) {
                delete next[i];
            }
        }
     
        void insert(string s) {
            int len = s.length();
            Node* cur = this;
            for (int i = 0; i < len; i++) {
                if (cur->next[s[i] - 'a'] == NULL) {
                    cur->next[s[i] - 'a'] = new Node();
                }
                cur = cur->next[s[i] - 'a'];
            }
            cur->end = true;
        }     
    };
     
    class Solution {
    public:
        bool wordBreak(string s, unordered_set<string> &dict) {
            Node root;
            int len = s.length();
            vector<bool> vec(len, false);
            for (auto it = dict.begin(); it != dict.end(); it++) {
                root.insert(*it);
            }
            findMatch(s, &root, vec, 0);
            for (int i = 0; i < len; i++) {
                if (vec[i]) findMatch(s, &root, vec, i + 1);
            }
            return vec[len - 1];
        }
     
        void findMatch(const string& s, Node* cur, vector<bool>& vec, int start) {
            int i = start;
            int len = s.length();
            while (i < len) {
                if (cur->next[s[i] - 'a'] != NULL) {
                    if (cur->next[s[i] - 'a']->end) { vec[i] = true; }
                    cur = cur->next[s[i] - 'a'];
                }
                else break;
                i++;
            }
        }
    };

    第二刷:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    class Solution {
    public:
        bool wordBreak(string s, unordered_set<string> &dict) {
            vector<vector<int> > canBreak; // 0 for unvisited, 1 for true, -1 for false
            int N = s.size();
            canBreak.resize(N);
            for (int i = 0; i < N; i++)
            {
                canBreak[i].resize(N);
            }
            return wordBreakRe(s, dict, canBreak, 0, N - 1);
        }
         
        bool wordBreakRe(string &s, unordered_set<string> &dict, vector<vector<int> > &canBreak, int start, int end)
        {
            if (canBreak[start][end] != 0)
                return (canBreak[start][end] == 1 ? true : false);
            string sub = s.substr(start, end - start + 1);
            if (dict.find(sub) != dict.end())
            {
                canBreak[start][end] = 1;
                return true;
            }
            for (int i = start; i < end; i++)
            {
                if (wordBreakRe(s, dict, canBreak, start, i) &&
                    wordBreakRe(s, dict, canBreak, i + 1, end))
                {
                    canBreak[start][end] = 1;
                    return true;
                }
            }
            canBreak[start][end] = -1;
            return false;
        }
    };

      

  • 相关阅读:
    shell 远程调用脚本
    Shell 特殊符号
    Centos 7 安全加固命令行
    unix2dos
    这都是啥啥啥
    发现一个识图比较厉害的网站
    Java 中用正则表达式修改 Email 地址
    PHP 7.0 中各种 Hash 速度比较
    利用create_ap软件创建无线AP
    &#129418; 自用Firefox和AdBlockPlus黑白名单
  • 原文地址:https://www.cnblogs.com/forcheryl/p/3997304.html
Copyright © 2020-2023  润新知