叶子结点

剑指offer——java刷题总结【三】

最后都变了- 提交于 2020-01-19 03:36:07
Note 题解汇总: 剑指offer题解汇总 代码地址: Github 剑指offer Java实现汇总 点击目录中的题名链接可直接食用题解~ 有些解法博文中未实现,不代表一定很难,可能只是因为博主太懒```(Orz) 如果博文中有明显错误或者某些题目有更加优雅的解法请指出,谢谢~ 目录 题号 题目名称 21 栈的压入、弹出序列 22 从上往下打印二叉树 23 二叉搜索树的后序遍历序列 24 二叉树中和为某一值的路径 25 复杂链表的复制 26 二叉搜索树与双向链表 27 字符串的排列 28 数组中出现次数超过一半的数字 29 最小的K个数 30 连续子数组的最大和 正文 21、栈的压入、弹出序列 题目描述 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的) 题目分析 解法一: 设置一个指向pop数组的index指针,遍历push数组,针对每一个遍历值做如下操作: 1、将当前遍历值压入栈中; 2、查看栈顶元素和pop数组的当前弹出值是否相等,如果相等则模拟出栈操作,将stack的栈顶元素弹出,并对pop数组的指针进行后移

递归与非递归及其相互转换

蓝咒 提交于 2020-01-18 15:48:13
一、什么是递归 递归是指某个函数直接或间接的调用自身。问题的求解过程就是划分成许多相同性质的子问题的求解,而小问题的求解过程可以很容易的求出,这些子问题的解就构成里原问题的解了。 二、递归的几个特点 1. 递归式,就是如何将原问题划分成子问题。 2. 递归出口,递归终止的条件,即最小子问题的求解,可以允许多个出口。 3. 界函数,问题规模变化的函数,它保证递归的规模向出口条件靠拢 三、递归的运做机制 很明显,很多问题本身固有的性质就决定此类问题是递归定义,所以递归程序很直接算法程序结构清晰、思路明了。但是递归的执行过程却很让人费解,这也是让很多人难理解递归的原因之一。由于递归调用是对函数自身的调用,在一次调用没有结束之前又开始了另外一次调用, 按照作用域的规定,函数在执行终止之前是不能收回所占用的空间,必须保存下来,这也就意味着每一次的调用都要把分配的相应空间保存起来。 为了更好管理这些空间,系统内部设置一个栈,用于存放每次函数调用与返回所需的各种数据, 其中主要包括函数的调用结束的返回地址,返回值,参数和局部变量等。 其过程大致如下: 1. 计算当前函数的实参的值 2. 分配空间,并将首地址压栈,保护现场 3. 转到函数体,执行各语句,此前部分会重复发生(递归调用) 4. 直到出口,从栈顶取出相应数据,包括,返回地址,返回值等等 5. 收回空间,恢复现场

Leetcode 系列之 Path Sum

时光总嘲笑我的痴心妄想 提交于 2020-01-18 04:09:33
现在来尝试将一系列的题目解决一下. Path Sum 本题是 easy 难度的题目, 给定一个二叉树和一个和 sum, 判断是否有一条从根结点到叶子结点的路径, 使得路径上的结点的值之和与 sum 相等. 使用递归的思路 : class Solution { public boolean hasPathSum(TreeNode root, int sum) { if (root == null) return false; if (root.left == null && root.right == null && root.val == sum) return true; return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val); } } 不使用递归, 使用栈的思路 : class Solution { public boolean hasPathSum(TreeNode root, int sum) { Stack<TreeNode> nodes = new Stack<>(); Stack<Integer> nums = new Stack<>(); nodes.push(root); nums.push(sum); while(!nodes.isEmpty()

折半查找判定树

和自甴很熟 提交于 2020-01-18 02:45:14
具有n个结点的折半查找树的高度为 给定一棵树,该树的ASLsucc=(1+2 2+3 4+4*4)/11=33/11=3 基本思想 : 在有序表中(low, high,low<=high), 取中间记录作为比较对象, 若给定值与中间记录的关键码相等,则查找成功; 若给定值小于中间记录的关键码,则在中间记录的左半区继续查找; 若给定值大于中间记录的关键码,则在中间记录的右半区继续查找。 不断重复上述过程,直到查找成功,或所查找的区域无记录,查找失败。 判定树 :折半查找的过程可以用二叉树来描述, 树中的每个结点对应有序表中的一个记录, 结点的值为该记录在表中的位置 判定树的构造过程 通常称这个描述折半查找过程的二叉树为折半查找判定树,简称判定树。 ⑴ 当n=0时,折半查找判定树为空; ⑵ 当n>0时, 折半查找判定树的根结点为mid=(n+1)/2, 根结点的左子树是与有序表r[1] ~ r[mid-1]相对应的折半查找判定树, 根结点的右子树是与r[mid+1] ~ r[n]相对应的折半查找判定树。 判定树的性质 任意两棵折半查找判定树,若它们的结点个数相同,则它们的结构完全相同 具有n个结点的折半查找树的高度为 任意结点的左右子树中结点个数最多相差1 任意结点的左右子树的高度最多相差1 任意两个叶子所处的层次最多相差1 来源: CSDN 作者: 张同学1111 链接: https

树的基础概念

为君一笑 提交于 2020-01-17 05:11:51
树的定义 树:n(n≥0)个结点的有限集合。 当n=0时,称为空树; 任意一棵非空树满足以下条件: ⑴ 有且仅有一个特定的称为根的结点; ⑵ 当n>1时,除根结点之外的其余结点被分成m(m>0)个互不相交的有限集合T1,T2,… ,Tm,其中每个集合又是一棵树,并称为这个根结点的子树。 叶子结点 :度为0的结点,也称为终端结点。 分支结点 :度不为0的结点,也称为非终端结点。 **孩子、双亲:**树中某结点子树的根结点称为这个结点的孩子结点,这个结点称为它孩子结点的双亲结点; 结点的度 :结点所拥有的子树的个数。 树的度 : 树中各结点度的最大值。 孩子、双亲 :树中某结点子树的根结点称为这个结点的孩子结点,这个结点称为它孩子结点的双亲结点 兄弟 :具有同一个双亲的孩子结点互称为兄弟。 同构 :对两棵树,若通过对结点适当地重命名,就可以使这两棵树完全相等 (结点对应相等,结点对应关系也相等),则称这两棵树同构。 树的存储结构 : 双亲表示法 孩子表示法-多重链表表示法(节点中的指针域表示孩子) 孩子兄弟表示法 **路径:**如果树的结点序列n1, n2, …, nk有如下关系:结点ni是ni+1的双亲(1<=i<k),则把n1, n2, …, nk称为一条由n1至nk的路径;路径上经过的边的个数称为路径长度。 祖先、子孙 :在树中,如果有一条路径从结点x到结点y

排序六 堆排序

血红的双手。 提交于 2020-01-16 10:36:56
目录 堆的概念 要点 算法分析   堆排序算法的总体情况   时间复杂度   算法稳定性 完整参考代码   JAVA版本 参考资料 相关阅读   说明 堆的概念 在介绍堆排序之前,首先需要说明一下,堆是个什么玩意儿。 堆 是一棵 顺序存储 的 完全二叉树 。 其中每个结点的关键字都 不大于 其孩子结点的关键字,这样的堆称为 小根堆 。 其中每个结点的关键字都 不小于 其孩子结点的关键字,这样的堆称为 大根堆 。 举例来说,对于n个元素的序列{R0, R1, ... , Rn}当且仅当满足下列关系之一时,称之为堆: (1) Ri <= R2i+1 且 Ri <= R2i+2 ( 小根堆) (2) Ri >= R2i+1 且 Ri >= R2i+2 ( 大根堆) 其中i=1,2,…,n/2向下取整; 如上图所示,序列R{3, 8, 15, 31, 25}是一个典型的小根堆。 堆中有两个父结点,元素3和元素8。 元素3在数组中以R[0]表示,它的左孩子结点是R[1],右孩子结点是R[2]。 元素8在数组中以R[1]表示,它的左孩子结点是R[3],右孩子结点是R[4],它的父结点是R[0]。可以看出,它们 满足以下规律 : 设当前元素在数组中以 R[i] 表示,那么, (1) 它的 左孩子结点 是: R[2*i+1] ; (2) 它的 右孩子结点 是: R[2*i+2] ; (3) 它的

决策树

泪湿孤枕 提交于 2020-01-16 09:01:53
策树法(Decision Tree) [ 编辑 ] 什么是决策树?    决策树(decision tree) 一般都是自上而下的来生成的。每个 决策 或事件(即自然状态)都可能引出两个或多个事件,导致不同的结果,把这种决策分支画成图形很像一棵树的枝干,故称决策树。   决策树就是将决策过程各个阶段之间的结构绘制成一张箭线图,我们可以用下图来表示。      选择分割的方法有好几种,但是目的都是一致的:对目标类尝试进行最佳的分割。   从根到叶子节点都有一条路径,这条路径就是一条“规则”。   决策树可以是二叉的,也可以是多叉的。   对每个节点的衡量:   1) 通过该节点的记录数   2) 如果是叶子节点的话,分类的路径   3) 对叶子节点正确分类的 比例   有些规则的效果可以比其他的一些规则要好。 [ 编辑 ] 决策树的构成要素 [1]   决策树的构成有四个要素:(1)决策结点;(2)方案枝;(3)状态结点;(4)概率枝。如图所示:      总之,决策树一般由方块结点、圆形结点、方案枝、概率枝等组成,方块结点称为决策结点,由结点引出若干条细支,每条细支代表一个方案, 称为方案枝;圆形结点称为状态结点,由状态结点引出若干条细支,表示不同的自然状态,称为概率枝。每条概率枝代表一种自然状态。在每条细枝上标明客观状态 的内容和其出现概率

递归 VS 非递归 内涵

空扰寡人 提交于 2020-01-16 05:13:08
递归与非递归转换的基础知识是能够正确理解三种树的遍历方法:前序,中序和后序,第一篇就是关于这三种遍历方法的递归和非递归算法。 一、为什么要学习递归与非递归的转换的实现方法? 1)并不是每一门语言都支持递归的。 2)有助于理解递归的本质。 3)有助于理解栈,树等数据结构。 二、三种遍历树的递归和非递归算法 递 归与非递归的转换基于以下的原理:所有的递归程序都可以用树结构表示出来。需要说明的是,这个”原理”并没有经过严格的数学证明,只是我的一个猜 想,不过在至少在我遇到的例子中是适用的。学习过树结构的人都知道,有三种方法可以遍历树:前序,中序,后序。理解这三种遍历方式的递归和非递归的表达方 式是能够正确实现转换的关键之处,所以我们先来谈谈这个。需要说明的是,这里以特殊的二叉树来说明,不过大多数情况下二叉树已经够用,而且理解了二叉树的 遍历,其它的树遍历方式就不难了。 1)前序遍历 a)递归方式: void preorder_recursive(Bitree T) /* 先序遍历二叉树的递归算法 */ { if (T) { visit(T); /* 访问当前结点 */ preorder_recursive(T->lchild); /* 访问左子树 */ preorder_recursive(T->rchild); /* 访问右子树 */ } } b)非递归方式 void preorder

二叉树的排序

痴心易碎 提交于 2020-01-15 04:19:11
一. 二叉树定义 二叉树是一个连通的无环图,并且每一个顶点的度不大于3。有根二叉树还要满足根结点的度不大于2。有了根结点之后,每个顶点定义了唯一的父结点,和最多2个子结点。然而,没有足够的信息来区分左结点和右结点。如果不考虑连通性,允许图中有多个连通分量,这样的结构叫做森林。 二. 二叉树类型 (1) 完全二叉树——若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到右依次排布,这就是完全二叉树。 (2) 满二叉树——除了叶结点外每一个结点都有左右子叶且叶子结点都处在最底层的二叉树。 (3) 平衡二叉树——平衡二叉树又被称为AVL树(区别于AVL算法),它是一棵二叉排序树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。 三. 二叉树的排序 节点类 创建树的方法 三种排序方法 Main类调用 来源: CSDN 作者: 怣*痛 链接: https://blog.csdn.net/cxy_12s/article/details/103901584

一步步地分析排序——优先队列和堆排序

断了今生、忘了曾经 提交于 2020-01-15 03:55:00
本文框架 定义和使用场景 优先队列是一个抽象数据类型,和栈、队列类似,它们都是抽象数据类型,相当于一个Java类,有自己的属性,并对外提供API。在了解它有什么API之前,先来看看优先队列的使用场景。 优先队列适用于需要对集合不断地执行插入元素、删除最大(或最小)元素的场景。这个场景大体可以分为两类: 第一类是业务实际情况需要,比如CPU的任务调度,待执行的任务是一个集合,每启动一个新程序就是在向集合里面插入元素。当前程序执行完后,就要从集合里面取出下一个优先级最高的程序。不断地有程序被启动和被执行,就像不断地对集合执行插入、删除最大元素的操作。 第二类场景是“从N个元素里获取最大的M个元素,N很大,不能一次性全部读进内存”,比如从银行成百上千万条交易记录里面找到金额最大的10笔交易;或者从全国的手机号码里面找到使用年限最长的10个号码。对于第二类场景,问题本身并不需要不断地对集合进行插入、删除操作。如果内存没有限制的话,你可以一次性将数据全部装进集合,然后随便选择一个排序算法对集合进行降序排列,接着输出最前面的10个元素。但是由于待处理的数据量过大(相对内存而言),不能使用排序算法解决该类问题,以银行交易记录为例子,你可以用优先队列通过如下步骤解决: 创建一个容量为11的集合 向集合里插入一笔交易记录,如果插入后集合的元素达到11个,删除金额最小的一笔交易( 需要注意的是