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

    }

};

  

你可能感兴趣的:(LeetCode)