给出一个由S个不同单词组成的字典和一个长字符串,把这个字符串分解成若干个单词的连接(单词可以重复使用),有多少种方法?比如4个单词 a、b、cd、ab 则 abcd 有两中分解方法:a+b+cd 和 ab + cd。
参考文献:《算法竞赛入门经典训练指南》P208,刘汝佳,陈锋
public class Trie {
private final static int MAX_SIZE = 1024;
private final static int SET_SIZE = 26;
protected int[][] tree = null;
protected int[] val = null;
protected int size = 0;
public Trie() {
tree = new int[MAX_SIZE][SET_SIZE];
val = new int[MAX_SIZE];
size = 1;
initNode(0);
}
protected int index(char ch) {
return ch - 'a';
}
// 初始化一个Tire树的结点,将其所有边置为无效状态0
private void initNode(int i) {
for ( int j=0; j< SET_SIZE; j++ ) {
tree[i][j] = 0;
}
val[i] = 0;
}
// 向Trie树增加一个字符串
public synchronized void insert(String s) {
if ( s == null )
throw new IllegalArgumentException();
int cur = 0, i = 0;
for ( i=0; i<s.length(); i++ ) {
char ch = s.charAt(i);
if ( tree[cur][index(ch)] == 0 ) {
initNode(size);
tree[cur][index(ch)] = size;
size++;
}
cur = tree[cur][index(ch)];
}
val[cur]++;
}
// 查询字符串是否在Trie树
public synchronized boolean query(String s) {
if ( s == null )
throw new IllegalArgumentException();
int cur = 0, i = 0;
for ( i=0; i<s.length(); i++ ) {
char ch = s.charAt(i);
if ( tree[cur][index(ch)] == 0 ) {
return false;
}
cur = tree[cur][index(ch)];
}
return ( val[cur] > 0 );
}
// 打印Trie树
public synchronized void print() {
for ( int i=0; i<size; i++ ) {
System.out.printf("%d[%d]: ", i, val[i]);
for ( int j=0; j<SET_SIZE; j++ ) {
if ( tree[i][j] > 0 )
System.out.printf("%c-%d ", j+'a', tree[i][j]);
}
System.out.println();
}
}
/**
* @param args
*/
public static void main(String[] args) {
String[] strs = { "a", "to", "tea", "ted", "ten", "i", "in", "inn" };
Trie inst = new Trie();
for ( String s : strs ) inst.insert(s);
inst.print();
for ( String s : strs ) System.out.printf("%s - %b%n", s, inst.query(s));
System.out.println(inst.query("abcdefg"));
}
}
public class RememberTheWord_LA_3942 extends Trie {
public int solve(String s) {
int[] res = new int[s.length()+1];
res[s.length()] = 1;
for ( int i=s.length()-1; i>=0; i-- ) {
int sum = 0;
int k = i, cur = 0;
while ( k < s.length() ) {
char ch = s.charAt(k);
if ( tree[cur][index(ch)] == 0 ) {
// 从当前结点出发,沿s[k]字符边无效
break;
}
// 从当前结点出发,沿s[k]字符边至下一结点
cur = tree[cur][index(ch)];
k++;
// 在下一结点匹配上了一个单词
if ( val[cur] > 0 ) {
sum += res[k];
}
}
res[i] = sum;
}
return res[0];
}
/**
* @param args
*/
public static void main(String[] args) {
RememberTheWord_LA_3942 inst = new RememberTheWord_LA_3942();
String[] strs = {"a","b","cd","ab"};
for ( String s : strs ) inst.insert(s);
int r = inst.solve("abcd");
System.out.println(r);
}
}