算法笔记——左神初级(9)前缀树结构介绍、字典序

前缀树

前缀树一般指字典树 这是指一种结构而不是一类题

又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。 注意信息在路上

它有3个基本性质:

  1. 根节点不包含字符,除根节点外每一个节点都只包含一个字符;
  2. 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串;
  3. 每个节点的所有子节点包含的字符都不相同。

在这里插入图片描述
前缀树用上图进行理解,其中节点均用圆圈表示,“abc”等字符加入到整棵树中作为路径加入,而不是以节点形式加入,同时每个字符在加入时均从头结点出发,因此可以看到“abc”和“bce”为两个分支,同时“abc”和“abd”前半段为一个分支,最后形成两个分支。

扩充功能:

  1. 将加入的字符以路径的形式加入节点可以存放是否为字符串结束为止的信息,从而可以在加入“be”这种跟之前走过的路径相同,但是没有最后形成新的分支的字符串统计出数目,最后可以用于整体加入了多少字符串信息的统计。(扩展了字符串加了几次的功能)
  2. 查询到达的前缀,加的过程中,到达了该节点几次

代码如下:

public static class TrieNode{
	public int path;  //有多少个字符串到达过这个节点
	public int end;   //有多少个字符串以这个节点结尾
	public TrieNode[] nexts;  //

	public TrieNode(){
		path = 0;
		end = 0;
		//这里指的是路,每个题具体分析,这里将26个字母作为26条路
		nexts = new TrieNode[26];
	}
}

public static class Trie{
	private TrieNode root;

	public Trie(){
		//新建的头,就是整体的头节点
		root = new TrieNode();
	}

	//插入一条字符串
	public void insert(String word){
		if(word == null){
			return;
		}
		char[] chs = word.toCharArray(); //word转为字符数组,开始跑
		TrieNode node = root;  //根节点,它的path和end不包含信息
		int index = 0;
		for(int i =0;i<chs.length;i++){
			//用ASCII码和a的差值来表示字母,a--0,b--1,c--2,z--25
			index = chs[i] - 'a';
			//判断当前节点是否有通向chs[i]这个字母的路
			if(node.nexts[index] == null){
				node.nexts[index] = new TrieNode(); //没有就新建路
			}
			node = node.nexts[index];
			node.path++;
		}
		node.end++;
	}
	
	//删除
	public void delete(String word){
		if(search(word) != 0){  //先查有没有  
			char[] chs = word.toCharArray();
			TrieNode node = root;
			int index = 0;
			for(int i = 0;i<chs.length;i++){
				index = chs[i] - 'a';
				//路径信息某个节点减一变成0,
				//意味着接下来的字符串全部都是所需要删除的字符串,
				//所以下面的字符串直接设置为null
				if(--node.nexts[index].path == 0){
					node.nexts[index] = null;
					return;
				}
				node = node.nexts[index];
			}
			node.end--;
		}
	}
	
	//查找一个word在其中出现过几次
	public int search(String word){ 
		if(word == null){
			return ;
		}
		char[] chs = word.toCharArray();
		TrieNode node = root;
		int index = 0;
		for(int i = 0;i<chs.length;i++){
			index = chs[i] - 'a';
			if(node.nexts[index] == null){
				return 0; //在任何一步遇到空,说明没插入过
			}
			node = node.nexts[index];
		}
		return node.end;  //遇到最后返回end
	}

	public int prefixNumber(String pre){
		if(pre == null){
			return 0;
		}
		char[] chs = pre.toCharArray();
		TrieNode node = root;
		int index = 0;
		for(int i = 0;i<chs.length;i++){
			index = chs[i] - 'a';
			if(node.nexts[index] == null){
				return 0;
			}
			node = node.nexts[index];
		}
		return node.path;
	}
}

题目:字符串数组拼接具有最低的字典序

【题目】给定一个字符串类型的数组strs,找到一种拼接方式,使得把所有字符串拼起来之后形成的字符串具有最低的字典序。

这里开始接触 贪心算法 以后不需要证明贪心策略,直接使用对数器验证正确性即可。

这里是将两个字符串整合起来之后再进行排序,而不是仅仅两个字符串比较直接排序最后整合。
【思路】按照 str1拼接str2<str2拼接str1,则str1在前,str2在后的顺序来排序。

public static class MyComparator implements Comparator<String> {
	@override
	public int compare(String a,String b){  //这里新建了一个比较器。
		return(a+b).compareTo(b+a);
	}
}

public static String lowestString(String[] strs){
	if(strs == null || strs.length == 0){
		return " ";
	}
	//字符串数组按照自己设计的比较器来排序
	Arrays.sort(strs,new MyComparator());  
	String res = " ";
	for(int i = 0;i<strs.length;i++){
		res += strs[i];
	}
	return res;
}

发布了27 篇原创文章 · 获赞 4 · 访问量 818

猜你喜欢

转载自blog.csdn.net/qq_25414107/article/details/104581739