Remember the word, LA 3942, Trie Tree

给出一个由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);
	}

}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值