您的位置:首页 > 其它

[leetcode]Word Break

2013-10-16 00:19 295 查看
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;
}
};


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: