zoukankan      html  css  js  c++  java
  • [leetcode]Word Break

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

    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的子串是否能分割。

    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表示这里是一个字符串的终结。

    #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++;
            }
        }
    };
    

    第二刷:

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

    Python3

    class Solution:
        def wordBreak(self, s: str, wordDict: List[str]) -> bool:
            memo = {}
    
            for i in range(len(s) + 1): # i for length of substr
                if i == 0:
                    memo[i] = True
                else:
                    isMatch = False
                    for word in wordDict:
                        if i - len(word) < 0:
                            continue
                        if memo[i - len(word)] and s[i - len(word): i] == word:
                            isMatch = True
                            break
                    memo[i] = isMatch
                    
            return memo[len(s)]
    

      

  • 相关阅读:
    windows下安装nginx
    java 32位MD5加密的大写字符串
    eclipse运行maven的jetty插件内存溢出
    Phpstorm Alt+Enter 自动导入类
    CSS 再学习,文本处理
    1406 data too long for column 'content' at row 1
    tp5.1报错 页面错误!请稍后再试
    lnmp升级php
    Tp5,Service使用
    CSS再学习 之背景色 背景图片
  • 原文地址:https://www.cnblogs.com/lautsie/p/3371354.html
Copyright © 2011-2022 走看看