[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)]

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM