算法入门篇七 前缀树

牛客网 左程云老师的算法入门课

找二叉树的节点的后继节点

原则

  • 如果节点有右子树,那么后继节点就是右子树的最左边的第一个节点
  • 如果节点没有右子树,如果节点是父节点的右孩子,就继续往上找,直到找到一个父节点是沿途节点的父节点,且沿途节点是其的左孩子

题目要求

新的二叉树的类型如下

public class Node{public int value;public Node left;public Node right;public Node parent;public Node(int val){value = val;}
}
  • 比传统的二叉树节点相比,多了一个指向父节点的parent指针
  • 头节点的parent指向空
  • 只有一个二叉树节点的node,请实现返回node节点的后继函数。二叉树的中序遍历中,node的下一个节点叫做节点的后继节点。请编写程序实现此功能: 

代码

package class05;public class Code08_SuccessorNode {public static class Node {public int value;public Node left;public Node right;public Node parent;public Node(int data) {this.value = data;}}public static Node getSuccessorNode(Node node) {if (node == null) {return node;}if (node.right != null) {return getLeftMost(node.right);} else { // 无右子树Node parent = node.parent;while (parent != null && parent.left != node) { // 当前节点是其父亲节点右孩子node = parent;parent = node.parent;}return parent;}}public static Node getLeftMost(Node node) {if (node == null) {return node;}while (node.left != null) {node = node.left;}return node;}public static void main(String[] args) {Node head = new Node(6);head.parent = null;head.left = new Node(3);head.left.parent = head;head.left.left = new Node(1);head.left.left.parent = head.left;head.left.left.right = new Node(2);head.left.left.right.parent = head.left.left;head.left.right = new Node(4);head.left.right.parent = head.left;head.left.right.right = new Node(5);head.left.right.right.parent = head.left.right;head.right = new Node(9);head.right.parent = head;head.right.left = new Node(8);head.right.left.parent = head.right;head.right.left.left = new Node(7);head.right.left.left.parent = head.right.left;head.right.right = new Node(10);head.right.right.parent = head.right;Node test = head.left.left;System.out.println(test.value + " next: " + getSuccessorNode(test).value);test = head.left.left.right;System.out.println(test.value + " next: " + getSuccessorNode(test).value);test = head.left;System.out.println(test.value + " next: " + getSuccessorNode(test).value);test = head.left.right;System.out.println(test.value + " next: " + getSuccessorNode(test).value);test = head.left.right.right;System.out.println(test.value + " next: " + getSuccessorNode(test).value);test = head;System.out.println(test.value + " next: " + getSuccessorNode(test).value);test = head.right.left.left;System.out.println(test.value + " next: " + getSuccessorNode(test).value);test = head.right.left;System.out.println(test.value + " next: " + getSuccessorNode(test).value);test = head.right;System.out.println(test.value + " next: " + getSuccessorNode(test).value);test = head.right.right; // 10's next is nullSystem.out.println(test.value + " next: " + getSuccessorNode(test));}}

二叉树的序列化/反序列化

  • 使用#代表null
  • 每输出一个数值,就输出一个_来隔离元素
  • 由树形结构到字符串的过程叫做序列化,由字符串到树形结构的过程是反序列化

代码

package class05;import java.util.LinkedList;
import java.util.Queue;public class Code09_SerializeAndReconstructTree {public static class Node {public int value;public Node left;public Node right;public Node(int data) {this.value = data;}}// 以head为头的树,请序列化成字符串返回public static String serialByPre(Node head) {if (head == null) {return "#_";}String res = head.value + "_";res += serialByPre(head.left);res += serialByPre(head.right);return res;}public static Node reconByPreString(String preStr) {String[] values = preStr.split("_");Queue<String> queue = new LinkedList<String>();for (int i = 0; i != values.length; i++) {queue.add(values[i]);}return reconPreOrder(queue);}public static Node reconPreOrder(Queue<String> queue) {String value = queue.poll();if (value.equals("#")) {return null;}Node head = new Node(Integer.valueOf(value));head.left = reconPreOrder(queue);head.right = reconPreOrder(queue);return head;}public static String serialByLevel(Node head) {if (head == null) {return "#!";}String res = head.value + "_";Queue<Node> queue = new LinkedList<Node>();queue.add(head);while (!queue.isEmpty()) {head = queue.poll();if (head.left != null) {res += head.left.value + "_";queue.add(head.left);} else {res += "#_";}if (head.right != null) {res += head.right.value + "_";queue.add(head.right);} else {res += "#_";}}return res;}public static Node reconByLevelString(String levelStr) {String[] values = levelStr.split("_");int index = 0;Node head = generateNodeByString(values[index++]);Queue<Node> queue = new LinkedList<Node>();if (head != null) {queue.add(head);}Node node = null;while (!queue.isEmpty()) {node = queue.poll();node.left = generateNodeByString(values[index++]);node.right = generateNodeByString(values[index++]);if (node.left != null) {queue.add(node.left);}if (node.right != null) {queue.add(node.right);}}return head;}public static Node generateNodeByString(String val) {if (val.equals("#")) {return null;}return new Node(Integer.valueOf(val));}// for test -- print treepublic static void printTree(Node head) {System.out.println("Binary Tree:");printInOrder(head, 0, "H", 17);System.out.println();}public static void printInOrder(Node head, int height, String to, int len) {if (head == null) {return;}printInOrder(head.right, height + 1, "v", len);String val = to + head.value + to;int lenM = val.length();int lenL = (len - lenM) / 2;int lenR = len - lenM - lenL;val = getSpace(lenL) + val + getSpace(lenR);System.out.println(getSpace(height * len) + val);printInOrder(head.left, height + 1, "^", len);}public static String getSpace(int num) {String space = " ";StringBuffer buf = new StringBuffer("");for (int i = 0; i < num; i++) {buf.append(space);}return buf.toString();}public static void main(String[] args) {Node head = null;printTree(head);String pre = serialByPre(head);System.out.println("serialize tree by pre-order: " + pre);head = reconByPreString(pre);System.out.print("reconstruct tree by pre-order, ");printTree(head);String level = serialByLevel(head);System.out.println("serialize tree by level: " + level);head = reconByLevelString(level);System.out.print("reconstruct tree by level, ");printTree(head);System.out.println("====================================");head = new Node(1);printTree(head);pre = serialByPre(head);System.out.println("serialize tree by pre-order: " + pre);head = reconByPreString(pre);System.out.print("reconstruct tree by pre-order, ");printTree(head);level = serialByLevel(head);System.out.println("serialize tree by level: " + level);head = reconByLevelString(level);System.out.print("reconstruct tree by level, ");printTree(head);System.out.println("====================================");head = new Node(1);head.left = new Node(2);head.right = new Node(3);head.left.left = new Node(4);head.right.right = new Node(5);printTree(head);pre = serialByPre(head);System.out.println("serialize tree by pre-order: " + pre);head = reconByPreString(pre);System.out.print("reconstruct tree by pre-order, ");printTree(head);level = serialByLevel(head);System.out.println("serialize tree by level: " + level);head = reconByLevelString(level);System.out.print("reconstruct tree by level, ");printTree(head);System.out.println("====================================");head = new Node(100);head.left = new Node(21);head.left.left = new Node(37);head.right = new Node(-42);head.right.left = new Node(0);head.right.right = new Node(666);printTree(head);pre = serialByPre(head);System.out.println("serialize tree by pre-order: " + pre);head = reconByPreString(pre);System.out.print("reconstruct tree by pre-order, ");printTree(head);level = serialByLevel(head);System.out.println("serialize tree by level: " + level);head = reconByLevelString(level);System.out.print("reconstruct tree by level, ");printTree(head);System.out.println("====================================");}
}

如何判断一棵子树是不是另外一棵二叉树的子树

  • KMP算法

折纸问题

要求

参考

代码

package class05;public class Code10_PaperFolding {public static void printAllFolds(int N) {printProcess(1, N, true);}// 递归过程,来到了某一个节点,// i是节点的层数,N一共的层数,down == true  凹    down == false 凸public static void printProcess(int i, int N, boolean down) {if (i > N) {return;}printProcess(i + 1, N, true);System.out.println(down ? "凹 " : "凸 ");printProcess(i + 1, N, false);}public static void main(String[] args) {int N = 3;printAllFolds(N);}
}

前缀树

  • 存储在边上,不是节点
  • 节点存放信息:pass创建节点的时候通过这个节点几次;end:当前节点是多少字符串的结尾
  • 沿途节点的pass++;末尾节点的end++;

例子

加入节点

  • 加入节点ab,使得沿途a之后节点p=3,沿途b之后节点p=2,e=1;
  • 加入节点bcs,使得沿途bc之后节点++,使得s的p=2,e=2;

实现功能

  • 可以查询abc加入的次数,看的是e的值
  • 可以查询以ab作为前缀的次数,看的是p的值

删除节点

  • 沿途节点的p值减1,被删除的节点的p减1,e减1;并且内存释放。

代码

package class07;import java.util.HashSet;public class Code01_TrieTree {public static class TrieNode {public int pass;public int end;// HashMap<Char, Node> nexts;// TreeMap<Char, Node> nexts;public TrieNode[] nexts;public TrieNode() {pass = 0;end = 0;// nexts[0] == null 没有走向‘a’的路// nexts[0] != null 有走向‘a’的路// ...// nexts[25] != null 有走向‘z’的路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();TrieNode node = root;node.pass++;int index = 0;for (int i = 0; i < chs.length; i++) { // 从左往右遍历字符index = chs[i] - 'a'; // 由字符,对应成走向哪条路if (node.nexts[index] == null) {node.nexts[index] = new TrieNode();}node = node.nexts[index];node.pass++;}node.end++;}public void delete(String word) {if (search(word) != 0) { // 确定树中确实加入过word,才删除char[] chs = word.toCharArray();TrieNode node = root;node.pass--;int index = 0;for (int i = 0; i < chs.length; i++) {index = chs[i] - 'a';if (--node.nexts[index].pass == 0) {// java C++ 要遍历到底去析构node.nexts[index] = null;// ...return;}node = node.nexts[index];}node.end--;}}public void deleteCPP(String word) {if (search(word) != 0) { // 确定树中确实加入过word,才删除char[] chs = word.toCharArray();TrieNode node = root;node.pass--;int index = 0;TrieNode a = null;int deleteIndex = -1;HashSet<TrieNode> deleteSet = new HashSet<>();for (int i = 0; i < chs.length; i++) {index = chs[i] - 'a';if (--node.nexts[index].pass == 0) {a = a == null ? node : a;deleteIndex = deleteIndex == -1 ? index : deleteIndex;deleteSet.add(node.nexts[index]);}node = node.nexts[index];}node.end--;a.nexts[deleteIndex] = null;// deleteSet ... 析构}}// word这个单词之前加入过几次public int search(String word) {if (word == null) {return 0;}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;}// 所有加入的字符串中,有几个是以pre这个字符串作为前缀的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.pass;}}public static void main(String[] args) {Trie trie = new Trie();System.out.println(trie.search("zuo"));trie.insert("zuo");System.out.println(trie.search("zuo"));trie.delete("zuo");System.out.println(trie.search("zuo"));trie.insert("zuo");trie.insert("zuo");trie.delete("zuo");System.out.println(trie.search("zuo"));trie.delete("zuo");System.out.println(trie.search("zuo"));trie.insert("zuoa");trie.insert("zuoac");trie.insert("zuoab");trie.insert("zuoad");trie.delete("zuoa");System.out.println(trie.search("zuoa"));System.out.println(trie.prefixNumber("zuo"));}}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/447211.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算法入门篇八 贪心算法

牛客网 左程云老师的算法入门课 贪心算法 贪心算法的解题步骤 例子 题目要求 解题策略 按照结束时间早的会议先安排&#xff0c;比如先安排【2&#xff0c;4】&#xff0c;当4结束了&#xff0c;所有开始时间小于4的全部淘汰&#xff0c;【1&#xff0c;7】、【3&#xff…

算法入门篇九 暴力递归

牛客网 左程云老师的算法入门课 暴力递归 原则 汉诺塔问题 问题 打印n层汉诺塔从左边移动到最右边的过程 思想 一共六个过程&#xff0c;左到右、左到中&#xff0c;中到左&#xff0c;中到右&#xff0c;右到左&#xff0c;右到中&#xff0c;互相嵌套使用 左到右 将1…

rtsp和sdp

RTSP 是由Realnetwork 和Netscape共同提出的如何有效地在IP网络上传输流媒体数据的应用层协议 。 实时流协议&#xff08;RTSP&#xff09;建立并控制一个或几个时间同步的连续流媒体&#xff0c;如音频和视频。尽管连续媒体流与控制流交叉是可能的&#xff0c;RTSP本身并不发…

使用javascript实现对于chineseocr的API调用

ChineseOCR在线API 网页地址 界面 提供多种接口调用方式&#xff0c;比如在线调用、Javascript api调用、curl api调用和python api调用四种方式&#xff0c;本次使用javascript api调用的方式进行OCR识别在线Javascript工具 在线工具网页链接在线Base64 转化工具 在线工具…

移动流媒体业务的技术与标准

1 引言   流媒体业务是从Internet上发展起来的一种多媒体应用&#xff0c;指使用流&#xff08;Streaming&#xff09;方式在网络上传输的多媒体文件&#xff0c;包括音频、视频和动画等。   流媒体传输技术的主要特点是以流&#xff08;streaming&#xff09;的形式进行多…

使用python实现对于chineseocr的API调用

ChineseOCR在线API 网页链接 界面 提供多种接口调用方式&#xff0c;比如在线调用、Javascript api调用、curl api调用和python api调用四种方式&#xff0c;本次使用javascript api调用的方式进行OCR识别在线Base64 转化工具 Base64在线小工具代码修改 新增一个变量fill_w…

算法入门篇十 图

图的存储方式 临接表临接矩阵 表达 点集/边集有向图/无向图 Graph&#xff08;大结构就是图&#xff09;&#xff08;包含点集合和边集合&#xff09; import java.util.HashMap; import java.util.HashSet;public class Graph {public HashMap<Integer, Node> nodes;…

超文本传输协议

超文本传输协议 超文本传输协议超文件传输协定(HTTP&#xff0c;HyperTextTransfer Protocol)是因特网上应用最为广泛的一种网络传输协定。所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。 目录 介绍请求信息请求方法安全方法超…

利用MFC调用libvlc.dll作一个简单的播放器

简单介绍MFC调用libvlc.dll作一个简单的播放器&#xff0c;抛砖引玉&#xff0c;各位VC达人继续深入研究&#xff0c;Jeremiah对VC确实不太感兴趣&#xff0c;所以就不做太深入的研究了。2009.10.29修改&#xff1a;加入clip_children属性设置。参开第1步。环境&#xff1a; …

使用Remix编写Solidity语言的小例子

设置数值/取数值/加法运算 讲解 uint默认使用256位数的整型view表示这个函数仅仅对于数据仅仅是读取&#xff0c;没有修改操作returns(uint )&#xff0c;如果单纯指定uint&#xff0c;返回的是函数体内的return值&#xff0c;如果包含uint sum,uint SAD_a&#xff0c;那么返…

RTP协议栈简介

流媒体指的是在网络中使用流技术传输的连续时基媒体&#xff0c;其特点是在播放前不需要下载整个文件&#xff0c;而是采用边下载边播放的方式&#xff0c;它是视频会议、IP电话等应用场合的技术基础。RTP是进行实时流媒体传输的标准协议和关键技术&#xff0c;本文介绍如何在L…

使用多线程的方式调用chineseocr_API

ChineseOCR在线API 网页链接 界面 提供多种接口调用方式&#xff0c;比如在线调用、Javascript api调用、curl api调用和python api调用四种方式&#xff0c;本次使用javascript api调用的方式进行OCR识别代码 import glob import base64 import os import requests import …

开源好代码 音视频

VirtualDub 一、简介 图1VirtualDub主界面 VirtualDub是一款开源的音视频捕获、处理软件。VirtualDub也可称为一款多媒体编辑软件&#xff0c;因为它包含了多媒体输入、编辑、处理、输出等各个环节&#xff0c;但是作者并未将它定位为一款多媒体编辑软件&#xff08;参见官网&a…

深入理解Solidity 二

Solidity数据位置 所有复杂的数据类型&#xff0c;即数组、结构和映射类型&#xff0c;都会有一个额外属性“数据位置”&#xff0c;用来指定数据的存储位置&#xff0c;即数据是存储在memory还是存储在storage里面根据上下文环境&#xff0c;IDE会自动指定数据的默认存储位置…

VOIP简介

一、什么是VOIP VOIP全称为&#xff08;VoiceOver Internet Protocol&#xff09;&#xff0c;是一种利用Internet网络进行语音通信的技术&#xff0c;更通俗一点说&#xff0c;就是IP电话。就是以IP分组交换网为传输平台&#xff0c;对模拟的语音信号进行编码压缩&#xff0c…

深入理解Solidity 三

Solidity函数声明和类型 函数的值类型有两类&#xff1a;内部&#xff08;internal&#xff09;类型和外部&#xff08;external&#xff09;类型内部函数只可以在当前合约内部被调用&#xff08;即在当前代码块内&#xff0c;包括内部库函数和继承函数&#xff09;&#xff0c…

安装solc模块4.25版本

使用国产阿里云的cnpm 如果不知道cnpm 参考链接 安装solc模块4.25版本 npm i solc0.4.25 --save -g查看安装是否成功 可以配置软连接使用solc&#xff0c;我的没有配置 solcjs --version

在pycharm中使用conda虚拟环境(conda虚拟环境是已经创建好的),解决python安装包文件很费劲的问题

查看conda的虚拟环境 使用PyCharm连接conda创建的虚拟环境&#xff0c;需要一个前提就是虚拟环境必须存在&#xff0c;使用conda env list命令查看虚拟环境列表打开PyCharm软件 打开pycharm&#xff0c;选择File->setting->Project:****->Project Interperter&#…

完成一个H.265/HEVC码流分析工具

经过大约一个月左右的业余时间&#xff0c;终于初步完成一个H.265/HEVC码流分析工具。时间包括平时的周末、晚上&#xff0c;以及调休的集中时间。当然&#xff0c;中秋回家过节不写代码。截至今天&#xff0c;经过多种H.265序列测试&#xff0c;也有各种工具对比&#xff0c;基…

Golomb及指数哥伦布编码原理介绍及实现

文章来源&#xff1a; https://www.cnblogs.com/wangguchangqing/p/6297792.html &#xff0c; 写的不错&#xff0c;转发出来。 2017年的第一篇博文。 本文主要有以下三部分内容&#xff1a; 介绍了Golomb编码&#xff0c;及其两个变种&#xff1a;Golomb-Rice和Exp-Golo…