1.前缀树(Trie Tree)

1.1 字符串生成前缀树的过程

字母是填在路上的,不是填在节点上的。

首先是一个空的头结点:

加入“abc”到这棵树中:

头结点有到a的路吗?没有,添加:

有a到b的路吗?没有,添加,c也一样:

接着添加字符串“bce”:

添加字符串“abd”:

添加字符串“bef”:

在添加N个字符串之后,可以查询,“某个字符串是否是以“be”开始的”。

若要查询“是否含有字符串“be”?”,原始的树结构,不足以实现这个功能。

  • 添加了“bef”,但是“be”的路径和“bef”的路径是重合的,无法判断有没有加过“be”。

需在节点处添加一个值,表示有多少个字符串是以这个字符结尾的。更改之后的树结构如下图:

此时b-e中e后面的节点值为0,说明没有加过"be"。

此树结构还可以查某个字符串加过几次。

“给出有多少个字符串以给定的额字符串作为前缀”——需要再加一个数据项:每一个节点被划过了多少次。

上述树结构,更改之后如下图所示:

添加字符串的代价:字符串本身的长度,和数据量N无关;

查某个字符的代价:字符串本身的长度,和数据量N无关;

1.2 代码实现

package Tree;public class TrieTree {public static void main(String[] args) {Trie trie = new Trie();System.out.println(trie.search("hello"));trie.insert("hello");System.out.println(trie.search("hello"));trie.delete("hello");System.out.println(trie.search("hello"));trie.insert("hello");trie.insert("hello");trie.delete("hello");System.out.println(trie.search("hello"));trie.delete("hello");System.out.println(trie.search("hello"));trie.insert("helloa");trie.insert("helloac");trie.insert("helloab");trie.insert("helload");trie.delete("helloa");System.out.println(trie.search("helloa"));System.out.println(trie.prefixNumber("hello"));}public static class TrieNode{public int path;public int end;public TrieNode[] nexts;//此节点有多少条通往下层的路//通过判断此节点的路径指向的节点是否为空来判断这条路是否存在public TrieNode() {this.path=0;this.end=0;this.nexts=new TrieNode[26];//26个字母就26条路}}public static class Trie{TrieNode root;public Trie() {root=new TrieNode();}public void insert(String str) {if(str==null)return;char[] arr=str.toCharArray();TrieNode node=root;int index=0;for(int i=0;i<arr.length;i++) {index=arr[i]-'a';//0~25if(node.nexts[index]==null)node.nexts[index]=new TrieNode();node=node.nexts[index];//node往下挑跳一个,i=0时是从头结点跳到第一个节点node.path++;}node.end++;//整个字符串加完之后,最后一个字符的end+1;}public int search(String str) {if(str==null)return 0;char[] arr=str.toCharArray();TrieNode node=root;int index=0;for(int i=0;i<arr.length;i++) {index=arr[i]-'a';//0~25if(node.nexts[index]!=null)node=node.nexts[index];elsereturn 0;}return node.end;}public void delete(String str) {if(search(str)==0)return;char[] arr=str.toCharArray();TrieNode node=root;int index=0;for(int i=0;i<arr.length;i++) {index=arr[i]-'a';//0~25if(--node.nexts[index].path==0) {//判断是否需要断掉这条路node.nexts[index]=null;return;}elsenode=node.nexts[index];}node.end--;}public int prefixNumber(String str) {if(str==null)return 0;char[] arr=str.toCharArray();TrieNode node=root;int index=0;for(int i=0;i<arr.length;i++) {index=arr[i]-'a';//0~25if(node.nexts[index]!=null)node=node.nexts[index];elsereturn 0;}return node.path;}}
}

运行结果:

2.贪心策略

(使用对数器严重贪心策略是否正确,不要纠结正确性证明)

贪心:根据某个标准分出个优先级,然后按照优先级的顺序执行。

2.1 举例

拼接字符串,使得结果为最小(按字典序)。

比如:"ab"、“cd”、"ef"三个字符串,拼接的结果可以由多种,但是”abcdef“这个结果才是最小的,题目中想要的。

2.1.1 分析

若先将字符串数组中的字符串拍好序再进行拼接,如下:

if(str1<=str2)str1连接str2;
elsestr2连接str1;

这种方式不对,因为:"b"<"ba",但是拼接之后"bba">"bab"。

所以正确的比较策略应该是:

if(str1连接str2<=str2连接str1)str1放前面;
elsestr2放前面;

即,谁作为前缀更小谁放前面。

2.1.2 代码实现

package Solution;import java.util.Arrays;
import java.util.Comparator;public class StrCon {public static void main(String[] args) {String[] strs1 = { "jibw", "ji", "jp", "bw", "jibw" };System.out.println(lowestString(strs1));String[] strs2 = { "ba", "b" };System.out.println(lowestString(strs2));}public static class MyComparator implements Comparator<String>{@Overridepublic int compare(String str1, String str2) {return (str1+str2).compareTo(str2+str1);/** compareTo* 如果指定的数与参数相等返回0。* 如果指定的数小于参数返回 -1。* 如果指定的数大于参数返回 1。*/}      }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;}
}

运行结果:

2.1.3 结论

当比较策略是个环时,不具有传递性,这个比较策略无效。

例如,有甲、乙、丙三个变量,订制的策略为:

  • 甲和乙:甲在前;
  • 乙和丙:乙在前;
  • 甲和丙:丙在前。

以上策略构成一个环。

要使得比较的结果唯一,则设定的比较策略要具有传递性,即:

  • a.b≤b.a
  • b.c≤c.b
  • 则:a.c≤c.a

以上式子中,将字符串等同于k进制的数:

  • 连接的结果为:
  • 即12乘以10(进制)的21长度(2)次方

则字符串拼接可以理解为:

,则上述的传递性规则可表示为:

化简:

由以上两个式子得:

由数的交换律和结合律可知:

所以:

化简结果:

得证。

要证明得到的字符串s是最小的字典序,即证明任意交换两个字符,得到的字典序都比s的字典序大。

以得到的最小字典序字符串结果为:,要证明肯定大于等于

在第一个串中,的前面,则:

若将交换:

一直换到挨着:

然后将b往前换:

最终:

所以,得到的结果已是最小。

算法练习day13——190401(前缀树、贪心策略拼接字符串使字典序最小)相关推荐

  1. 算法补天系列之——前缀树+贪心算法

    介绍前缀树 经典的前缀树,字符都是在路上的,节点是为了边的存在而存在的,有路就可以复用. 那么前缀树对应的数据结构是什么样的呢? 对于节点构建结构,设置一个int pass(表示路径途径这个节点的次数 ...

  2. 8-详解前缀树贪心算法N皇后问题

    一.何为前缀树?如何生成前缀树? 经典的前缀树:点上没有数据,如果有路就复用,没有路就新建. 前缀树点的结构: pass:代表这个点经过了多少次,根节点的pass代表有多少个字符串前缀为空,或者一共加 ...

  3. 算法入门篇七 前缀树

    牛客网 左程云老师的算法入门课 找二叉树的节点的后继节点 原则 如果节点有右子树,那么后继节点就是右子树的最左边的第一个节点 如果节点没有右子树,如果节点是父节点的右孩子,就继续往上找,直到找到一个父 ...

  4. 左程云算法 day8 前缀树和贪心算法

    前缀树 :建立好前缀树后可以把下面的题目快速地解决,便于实现前缀查找 题目:一个字符串类型的数组arr1,另一个字符串类型的数组arr2.arr2中有哪些字符,是arr1中出现的,请打印.arr2中有 ...

  5. 贪心策略--16经典问题总结!

    贪心算法 编号 题目 1货郎担 问题: 货郎担问题:假定有五个城市,已知费用矩阵如下,分别从五个城市出发,然后选取一条费用最小的线路,验证这种算法不能得到最优解. 贪心选择:每次选择之前没有走过的费用 ...

  6. 前缀树是什么 前缀树的使用场景

    前缀树的概述 前缀树又名字典树,单词查找树,Trie树,是一种多路树形结构,是哈希树的变种,和hash效率有一拼,是一种用于快速检索的多叉树结构. 典型应用是用于统计和排序大量的字符串(但不仅限于字符 ...

  7. C++简单实现 前缀树

    今天在leetcode上面看了一道题(第208题),问题是如何实现一个字符串前缀树,能够实现字符串的插入,查找和查找前缀功能.在这里记录一下前缀树的实现: class Trie { public:/* ...

  8. 前缀树(java实现)

    package class_07; /*** * 前缀树** 例子:* 一个字符串类型的数组arr1,另一个字符串类型的数组arr2.* arr2中有哪些字符,是arr1中出现的?请打印* arr2中 ...

  9. 数据结构与算法笔记:贪心策略之BSTBBST, Hashtable+Dictionary+Map, Priority Queue~Heap, Minium Spanning Tree

    BST & BBST BST(Binary Search Tree) 二叉搜索树,也就是使用二叉树来做查找 BBST(Balanced Binary Search Tree) 平衡二叉搜索树 ...

最新文章

  1. snmpd 子代理模式编译测试
  2. java 取上下文路径_取Servlet上下文路径,取WebContent的路径
  3. Spring Cloud Feign如何实现JWT令牌中继以传递认证信息
  4. JSONP解决跨域及ajax同步问题
  5. Marketing Cloud contact主数据的csv导入
  6. python读取html_从零开始的Python爬虫教程(一):获取HTML文档
  7. 怎么看电脑电源多少w_UPS不间断电源设备哪个品牌好?如何选购家用电脑UPS电源?UPS电源价格多少?...
  8. 【Python】pdf2image模块+poppler将PDF转换为图片
  9. 检索COM类工厂组件的CLSID 80040154(不容易啊!!) 80040154.
  10. storagesky存储天地
  11. UINavigationController_学习笔记
  12. Oracle 安装 RAC 11.2.0.4 centos7.4 -udev磁盘绑定/执行root脚本报错
  13. 系统架构图怎么画_产品架构图到底是怎么“画”出来的?
  14. 360安全浏览器安装adblock plus
  15. Memory Limit Exceeded
  16. 在windows平台上打造Linux开发环境-洋葱先生-杨少通
  17. 北大的戴威,为何输给了三本的胡玮炜?
  18. Meta 将使用微软 Azure 最新虚拟机 (VM) 系列,多达 5400 个 GPU
  19. opengl-PBR基于物理的渲染(Physically Based Rendering):理论基础
  20. sql server 不允许保存更改,您所做的更改要求删除并重新创建以下表 的解决办法

热门文章

  1. linux 安装tomcat 权限不足问题
  2. NOIp 2014 #2 联合权值 Label:图论 !!!未AC
  3. [译]Front-end-Developer-Interview-Questions
  4. 【01】Clean Code
  5. 第一课 前言 学PHP就是为了做网站
  6. HDU 2841 Visible Trees
  7. 从Windows到Linux
  8. mysql5.718解压版安装_MySQL v5.7.18 版本解压安装
  9. 一篇文章教你学会Java泛型
  10. 一篇文章教你学会Java基础I/O流