
算法
辛星
生命不息,奋斗不止。
展开
-
辛星Java树算法教程第零篇:树的表示
经过一段时间的纠结,辛星Java树算法终于开始更新了,本次从最简单的二叉树开始吧,其中也都是一些常见的知识点。本期的每节的篇幅都不会太长,主要是写起来比较轻盈简单。作为第一节,这里只介绍一下树的表示,这里的树我们可以用递归的方式来表示,即如下:package com.mengzhidu.teach.algorithm.tree.demo;/** * Created by xinxing ...原创 2019-03-20 22:20:36 · 304 阅读 · 3 评论 -
辛星Java树算法教程第十一篇:二叉树从下向上按层遍历
正常的分层遍历是从上向下,每一层从左到右。我们这里的分层是自下向上,每一层仍然从左到右。比如一棵树是这样的: A B C D E F那么从上到下,从左到右的输出就是:ABCDEF。那么从下到上,从左到右的输出就是:DEFBCA。其实这里的实现也比较简单,我们需要借助一个队列和一个栈,队列用来实现分层遍历,但是入队的时候我们是先入队右子树,然后入...原创 2019-04-08 21:11:54 · 905 阅读 · 3 评论 -
辛星Java树算法教程第十二篇:二叉树的最小深度
对于二叉树来说,所谓最小深度,就是树的叶子节点中到根节点的最小距离。这里说一下,空树返回0.如果一个二叉树只有右子树,则返回右子树上的叶节点的最小深度。如果一个二叉树只有左子树,则返回左子树上的叶节点的最小深度。如果一个二叉树有左右子树,则返回左右子树上的最小深度。我们当然可以使用递归的方式来做,我们也可以使用分层遍历的方式来解决。下面给出示例代码:package com.mengz...原创 2019-04-08 21:47:03 · 264 阅读 · 3 评论 -
辛星Java树算法第十五篇:二叉树是否为对称二叉树(递归与非递归)
对于二叉树是否左右对称,这里考察的主要是一个二叉树的左右子树对应节点的值是否相同。其实这个思路也很简单,一般可以分为递归的实现和非递归的实现。我们这里可以构建一棵对称的树,范例代码参考:package com.mengzhidu.teach.algorithm.tree.demo;/** * Created by xinxing on 2019/4/12 */public clas...原创 2019-04-15 19:00:00 · 359 阅读 · 4 评论 -
辛星Java树算法第十四篇:二叉树上路径和为某个值的所有路径
这是一道非常经典的题目,在《剑指offer》中也有收录,而且在各大博客中也有提及。路径和的使用还是非常广泛的,因为操作简单,灵活性强。首先我们要给出这种树的定义:package com.mengzhidu.teach.algorithm.tree.demo;/** * Created by xinxing on 2019/4/11 */public class NumTreeNod...原创 2019-04-12 19:58:36 · 258 阅读 · 2 评论 -
辛星Java动态规划教程第六篇:求最长递增子序列(LIS)的个数,时间复杂度O(n^2)
对于一个固定的序列来说,其最长递增子序列的长度是确定的,但是这样的最长递增子序列有多少个呢?这是一个值得思考的问题。先来看一个具体的问题吧,比如对于序列{1, 2, 5, 4, 7}来说,我们很容易知道,这个最长子序列有两个,即{1,2,5,7}和{1,2,4,7}。这里的裂变点,在于小于7的时候的最长递增子序列有两个。如果还不清楚,可以再看一个例子,比如序列 {1, 2, 5, 4, 7, ...原创 2019-04-26 12:04:20 · 787 阅读 · 4 评论 -
辛星Java动态规划教程第一篇:求斐波那切数列
对于理解动态规划来说,最简单的题目还是求斐波那切数列的第i个值。很多资料都把它作为一个印子,以此来介绍动态规划的基本定义。不过也有些书认为菲波那切数列过于简单,以致于不能让读者感受到动态规划的优美之处,所以选择了其他的例子。不管怎么说,我们这里还是以菲波那切数列来作为第一个印子,代码如下所示:package com.mengzhidu.teach.algorithm.dp.demo.line...原创 2019-04-17 21:08:11 · 373 阅读 · 4 评论 -
辛星Java动态规划教程第二篇:最长公共子序列(LCS)
最长公共子序列,即Longest Common Subsequence,通常简称为LCS。假如我们有两个子序列,比如{a,b,c,d,e,f}和{a,c,e,f,d},这里的最长公共子序列就是{a,c,e,f}。当然需要说明的是,最长公共子序列可能不止一个。常规的思路有两个:(1).使用一个二维数组来存储序列M和序列N的各自的位数的对应的最大长度,并且寻找一个递推关系,此时时间复杂度为O(...原创 2019-04-17 21:28:29 · 620 阅读 · 4 评论 -
辛星Java动态规划算法教程汇总【刷题用】
线性动规第一篇: 菲波那切数列https://blog.youkuaiyun.com/xinguimeng/article/details/89364875第二篇:最长公共子序列(LCS)https://blog.youkuaiyun.com/xinguimeng/article/details/89365332第三篇:最长公共子串第四篇: 最长递增子序列(LIS)第五篇: 最长公共子序列第二版(LCS...原创 2019-04-17 21:35:13 · 836 阅读 · 4 评论 -
辛星Java动态规划教程第三篇:最长公共子串(LCS)
上一篇介绍到最长公共子序列,这一篇就来介绍下最长公共子串,即最长公共子字符串。也就是Longest Common Substring,通常也被简称为LCS,比较尴尬的是和上一篇的简称是重名的。要求最长公共子串,思路有很多,这里介绍两种,但是实现上是相同的,只是初始思路不同:第一种,比较常规且自然的思路就是对于字符串a和b,构造一个二维数组arr,其中arr[i][j]表示第a[i]和b[j]是...原创 2019-04-22 22:00:23 · 890 阅读 · 3 评论 -
辛星Java动态规划教程第四篇:最长递增子序列(LIS),时间复杂度O(n^2)
相对于最长公共子序列和最长公共子串来说,最长递增子序列的解法就要多一些了。对于序列A来说,求它的递增子序列,比较简单的实现有很多种,我们本节介绍两种:第一种解法就是对这个序列做一次排序,变成一个递增序列B,这样求A和B的公共子序列就等价于求A的递增子序列。第二种解法就是使用动态规划的思路,这种思路也很多,可以维护一个长度为N的数组,这里的N的长度就是序列A的长度,它的每一项表示的是比序列A的...原创 2019-04-23 11:55:11 · 999 阅读 · 4 评论 -
辛星Java树算法第十三篇:判断二叉树是否为完全二叉树
对于完全二叉树,这里给一个来自百度百科的描述: 若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。我们可以根据题意做题即可,我们可以采用分层遍历的方式,在判断一个具体的节点的时候,我们可以有如下的判断依据:(1).如果这个节点的左子树为null,右子树不为null,则一定不是完全二叉树。(2).如...原创 2019-04-11 22:19:42 · 1131 阅读 · 3 评论 -
辛星Java树算法教程第十篇:二叉树的重建(带中序遍历)
对于重建二叉树的场景,通常是有中序遍历的,不然无法知道根节点在哪。因为前序遍历是根节点在最前面,后序遍历是根节点在最后面,所以无法明确的区分出来哪些点是左子树的点,哪些点是右子树的点。对于重建二叉树来说,这里我们选择以前序遍历和中序遍历为例进行说明。比如前序遍历为:A B D E C F比如中序遍历为:D B E A C F那么我们有如下的思维步骤:(1).根据前序遍历,我们知道A...原创 2019-04-07 04:29:32 · 214 阅读 · 4 评论 -
辛星Java树算法教程第一篇:树的前序遍历(递归方式与非递归方式)
二叉树的遍历分为三种:(1).前序遍历,即先遍历根节点,然后遍历左子树,最后遍历右子树。(2).中序遍历,即先遍历左子树,然后遍历根节点,最后遍历右子树。(3).后续遍历,即先遍历左子树,然后遍历右子树,最后遍历根节点。递归的实现方式就比较简单了,对于如下的二叉树: A / \ B C ...原创 2019-03-20 22:28:33 · 346 阅读 · 2 评论 -
辛星Java树算法教程第四篇:二叉树的后序遍历(非递归单栈方式)
对于二叉树的后序遍历,我们前面介绍了一种使用递归的方式,这种比较简单,还有两种使用栈的方式,但是这里都是选择了使用两个栈。那么能不能使用一个栈来完成呢?显然是可以呢。那么具体怎么操作呢?这里也有很多思路,我们这里介绍两种比较常规的思路。第一种是用一个临时变量来保存访问过的节点,它的主要目的是判断一个节点的左右子树是否均被访问完成。如果一个节点的左右子树均被访问了,那么我们就可以访问这个节点,...原创 2019-03-25 04:50:46 · 608 阅读 · 2 评论 -
辛星Java树算法教程第二篇:树的中序遍历(递归方式与非递归方式)
在上一篇中我们介绍了树的前序遍历,这一节我们介绍树的中序遍历。所谓树的中序遍历,就是先遍历左子树,然后遍历根节点,然后遍历右子树。我们先来看一下递归的实现方式(这里直接传入了空节点):package com.mengzhidu.teach.algorithm.tree.demo.traversal;import com.mengzhidu.teach.algorithm.tree.demo...原创 2019-03-22 10:37:09 · 222 阅读 · 1 评论 -
辛星Java树算法教程第五篇:二叉树的分层遍历
在介绍完深度遍历的三种(即前序遍历、中序遍历、后序遍历)之后,我们接下来介绍一下广度优先遍历,即分层遍历。分层遍历就是从上到下按层去遍历,每层都从左到右输出。其实这个也比较好实现,我们通过一个队列来保存即可。这里主要是通过上一层的顺序和下一层的顺序正好是相同的这一个特性,从而我们可以很轻松的在一个队列中实现。话不多说,直接给出代码实现吧:package com.mengzhidu.teac...原创 2019-03-26 12:15:17 · 263 阅读 · 3 评论 -
辛星Java树算法教程第三篇:树的后序遍历(递归方式与非递归方式的双栈方式)
到现在,树的深度遍历方式中就剩下树的后序遍历方式了,后序遍历也是三种遍历方式里面相对比较难的一个,也是思路相对比较多的一个。对于后序遍历,我们先给出一个递归的解法:package com.mengzhidu.teach.algorithm.tree.demo.traversal;import com.mengzhidu.teach.algorithm.tree.demo.TreeNode;...原创 2019-03-22 21:26:10 · 415 阅读 · 1 评论 -
辛星Java树算法教程汇总【刷题用,讲解较少】
第零篇 (树的表示):https://blog.youkuaiyun.com/xinguimeng/article/details/88701913第一篇 (二叉树的前序遍历 -> 递归与非递归):https://blog.youkuaiyun.com/xinguimeng/article/details/88702102第二篇 (二叉树的中序遍历 -> 递归与非递归):https://blog.c...原创 2019-03-29 22:39:18 · 446 阅读 · 2 评论 -
辛星Java树算法教程第六篇:二叉树的深度(递归与非递归,共三种思路)
所谓二叉树的深度,就是树的高度。如果只有一个根节点,那么树的深度就是1。如果左子树和右子树都非空,那么就是左子树和右子树的深度的最大值,再加上1,即根节点本身。一般来说,求解树的深度有三个大的思路,这里分别介绍一下吧:(1).采用递归的思路,分别求出左子树的深度和右子树的深度。(2).采用非递归的思路,这里可以使用深度遍历,这里我们可以用后序遍历。因为后序遍历的时候,左子树和右子树的深度是已...原创 2019-04-01 02:06:44 · 412 阅读 · 2 评论 -
辛星Java树算法教程第七篇:二叉树的宽度
所谓二叉树的宽度,就是相当于二叉树在分层遍历的时候,每一层都有自己的节点数,然后找出层数最大的那个。其实这里只需要借助于分层遍历即可,需要注意的是,我们需要知道什么时候开始一个新的层即可,常见的思路有两种,一种是保存每一层最左边的节点,一种是保存每一层的节点个数。如果是保存每一层的最左边的节点的话,我们只需要在一个循环里面判断即可。如果是保存每一层的节点个数的话,我们需要两个循环,即外循环是...原创 2019-04-05 23:03:50 · 619 阅读 · 2 评论 -
辛星Java树算法教程第八篇:二叉树的直径
在二叉树上的两个点,我们可以定义一个距离,即存在一条通路连接这两个点。那么对于一棵二叉树来说,会存在很多这样的距离,而最大的那个距离,我们可以称之为二叉树的直径。也有人会把二叉树的直径叫做二叉树的宽度,但是这样会很容易和另一个概念混淆。目前这两种说法都有,而我则是使用了直径和宽度的叫法来做区分。其实实现方式还是比较简单的:(1).如果直径通过了根节点,那么就是左子树的高度 + 右子树的高度...原创 2019-04-06 20:06:16 · 1036 阅读 · 3 评论 -
辛星Java树算法教程第九篇:二叉树的镜像(递归与非递归)
对于二叉树的镜像,也通常叫做二叉树的反转,这里采用了镜像的说法。它的操作方法就是把每个节点的左右子树进行交换。二叉树T和翻转后的二叉树T1会具有一个性质:T的中序遍历和翻转后T1的中序遍历的顺序正好是相反的。对于递归形式的二叉树的遍历比较简单,如下:package com.mengzhidu.teach.algorithm.tree.demo.basic;import com.men...原创 2019-04-06 20:42:00 · 332 阅读 · 3 评论 -
辛星Java动态规划教程第五篇:最长递增子序列(LIS),时间复杂度O(nlogn)
对于最长递增子序列的O(n^2)解法,前面已经介绍过了,相信大家都很好理解,那么接下来就要介绍时间复杂度为O(nlogn)的解法了。我们还是首先来介绍一下思路:我们保存一个数组arr,它的第i项表示可以组成长度为 i+1个自增子序列的最小的结尾的那个数,这个数组里面所存储的并不是原序列的最长递增子序列,它的顺序是错乱的。因为我们这里只要最长递增子序列的长度,这个长度就是这个数组arr里面有效...原创 2019-04-25 12:28:47 · 1215 阅读 · 4 评论