104. 二叉树的最大深度

题目描述 给定一个二叉树,找出其最大深度。 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。 说明: 叶子节点是指没有子节点的节点。 示例: 给定二叉树 [3,9,20,null,null,15,7], 3 / \ 9 20 / \ 15 7 返回它的最大深度 3 。 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/maximum-depth-of-binary-tree 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 解法1 – DFS 这是道经典的BinaryTree的模版题,我们声明函数private int helper(TreeNode node, int depth) ,当node是叶子结点时返回depth,如果node的左子树非空则递归调用helper(node.left, depth+1);当node的右子树非空,则递归调用helper(node.right, depth+1); 当node为空,则返回0。 时间复杂度O(n),空间复杂度O(n)。全部代码如下: 解法2 – BFS 当然这道题也可以用BFS来做,我们需要一个队列,还有一个Map<TreeNode, Integer>用来存放节点对应的深度。如果node的左子树非空,就将它如队列,然后depth+1放入map中;右子树同理。然后还需要一个存放答案的变量ans,如果取出节点的深度大于ans就更新它,最后返回ans。 复杂度和解法1相同,但因为用到了Map导致overhead比较大,实际运行时间比解法1慢很多。全部代码如下:

Read more

133. 克隆图

题目描述 给定无向连通图中一个节点的引用,返回该图的深拷贝(克隆)。图中的每个节点都包含它的值 val(Int) 和其邻居的列表(list[Node])。 示例: 输入: {“$id”:”1″,”neighbors”:[{“$id”:”2″,”neighbors”:[{“$ref”:”1″},{“$id”:”3″,”neighbors”:[{“$ref”:”2″},{“$id”:”4″,”neighbors”:[{“$ref”:”3″},{“$ref”:”1″}],”val”:4}],”val”:3}],”val”:2},{“$ref”:”4″}],”val”:1} 解释: 节点 1 的值是 1,它有两个邻居:节点 2 和 4 。 节点 2 的值是 2,它有两个邻居:节点 1 和 3 。 节点 3 的值是 3,它有两个邻居:节点 2 和 4 。 节点 4 的值是 4,它有两个邻居:节点 1 和 3 。 提示: 节点数介于 1 到 100 之间。 无向图是一个简单图,这意味着图中没有重复的边,也没有自环。 由于图是无向的,如果节点 p 是节点 q 的邻居,那么节点 q 也必须是节点p 的邻居。 必须将给定节点的拷贝作为对克隆图的引用返回。 来源:力扣(LeetCode)…

Read more

111. 二叉树的最小深度

题目描述 给定一个二叉树,找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说明: 叶子节点是指没有子节点的节点。 示例: 给定二叉树 [3,9,20,null,null,15,7], 3 / \ 9 20 / \ 15 7 返回它的最小深度  2. 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/minimum-depth-of-binary-tree 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 解法1 – DFS 解法1简单的很,我们就用DFS遍历二叉树,声明一个辅助函数用来遍历private int helper(TreeNode node, int depth)。node是当前节点,depth是当前节点深度。如果当前节点是叶节点,就返回depth;如果node左子树非空,就递归遍历左子树求最小深度;如果node右子树非空,就递归遍历右子树求最小深度,然后取左右子树最小深度的min并返回。 时间复杂度O(n),空间复杂度O(n)。全部代码如下: 解法2 – BFS 解法2用队列实现BFS,但是还需要用一个辅助的Map<TreeNode, Integer>记录节点与它的深度。首先从队列出队一个节点,然后从Map取出该节点深度currLevel。每当下一层的节点入队,就将被入队的节点作为key,currLevel+1作为value存入Map中。当发现出队的节点为叶节点时,就终止BFS过程,返回currLevel作为结果。 BFS遍历的好处是,如果首先碰到了叶节点就可以终止遍历过程。而DFS方式需要遍历所有节点才能够知道最小深度。但是最坏情况下BFS和DFS的时间复杂度是一样的,此外BFS还需要用Map存储节点与深度的对应关系,耗费额外的空间;而访问Map还会有一些开销,因此性能并没有DFS好。

Read more

129. 求根到叶子节点数字之和

题目描述 给定一个二叉树,它的每个结点都存放一个 0-9 的数字,每条从根到叶子节点的路径都代表一个数字。 例如,从根到叶子节点路径 1->2->3 代表数字 123。 计算从根到叶子节点生成的所有数字之和。 说明: 叶子节点是指没有子节点的节点。 示例 1: 输入: [1,2,3] 1 / \ 2 3 输出: 25 解释: 从根到叶子节点路径 1->2 代表数字 12. 从根到叶子节点路径 1->3 代表数字 13. 因此,数字总和 = 12 + 13 = 25. 示例 2: 输入: [4,9,0,5,1] 4 / \ 9 0  / \ 5 1 输出: 1026 解释: 从根到叶子节点路径 4->9->5 代表数字 495. 从根到叶子节点路径 4->9->1 代表数字…

Read more

101. 对称二叉树

题目描述 给定一个二叉树,检查它是否是镜像对称的。 例如,二叉树 [1,2,2,3,4,4,3] 是对称的。 1 / \ 2 2 / \ / \ 3 4 4 3 但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的: 1 / \ 2 2 \ \ 3 3 说明: 如果你可以运用递归和迭代两种方法解决这个问题,会很加分。 https://leetcode-cn.com/problems/symmetric-tree/ 解法1 为了解决问题,我们先画一个比较general的case来帮助我们思考。我们构建一个4层的对称二叉树,如图1所示。我们可以发现,如果一颗树是对称二叉树,那么它的左子树与右子树是互为镜像的。如图1所示,跟节点root的左子树root.left与右子树root.right互为镜像。因此,我们可以把问题转化为判断两个二叉树是否互为镜像。 为了判断两颗二叉树是否互为镜像,我们创建函数private boolean isMirror(TreeNode node1, TreeNode node2),用来判定两颗二叉树node1与node2是否互为镜像。那我们如何实现这个函数呢? 首先,如果node1与node2都是空,很好理解,他们是镜像的。 如果node1与node2有一个为空,另一个非空,那么肯定不是镜像的。 如果node1与node2都非空,但是node对应的值不想相等,那么也不互为镜像。 如果node1与node2非空,且值相等,那我们还需要递归的判断node1的右子树与node2的左子树互为镜像,且node1的左子树与node2的右子树互为镜像。 我们按照上面的规则递归的判定,直到我们都访问到叶节点后返回我们才能确定两棵树是互为镜像的。如果在递归的过程中发现有不符合上述规则都情况,那么这两棵树就不是镜像的。 下面的代码采用DFS方式判定,我们按照上面4条规则实现了isMirror函数,然后我们把root的左子树与右子树传递给isMirror函数就能够判定整棵树是否是对称的。 解法2 解法2采用另一个比较直观的思路,比较容易理解。我们观察图1,如果树是对称的,那么我们横向读取每一层的节点,都会发现他们是“回文序列”,也就是从左到右读和从右到左读都是一样的。如果有任何一层读起来不是回文序列,那么这棵树就不是对称的! 为了实现按层次遍历,我们使用BFS算法,用一个队列来实现。但是队列没法随机访问,我们在实现时使用数组来模拟队列。如果使用数组的remove方法来出队,会涉及到元素移动,使得时间复杂度达到O(n^2)。因此,我们采用“双缓冲”方法,创建变量queue以及buffer,从queue中读取当前层到节点并访问,将下一层节点放入buffer,然后交换queue与buffer。如果你不清楚二叉树层次变量,可以参考这个。 时间复杂度为O(n),空间复杂度为O(n)。全部代码如下:

Read more

102. 二叉树的层次遍历

题目描述 给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。 例如:给定二叉树: [3,9,20,null,null,15,7], 3 / \ 9 20 / \ 15 7 返回其层次遍历结果: [ [3], [9,20], [15,7] ] https://leetcode-cn.com/problems/binary-tree-level-order-traversal/ 解法1 – BFS 解法1不用多说,在课本中,考研题中经常出现。我们使用队列,将跟节点加入队列,然后出队并访问,再将出队节点的左右子树再一次加入队列……直到队列为空。这种解法很自然,也很容易想到。 时间复杂度O(n),空间复杂度O(n)。全部代码如下: 解法2 – DFS 这道题也可以采用DFS解法,层次其实就是深度,我们记录遍历到每一层级到深度,为每一层级创建List,根据当前深度找到对应的List,然后追加进去。在实现的时候,我们采用先序遍历的,如果采用中序/后序遍历,下面的代码需要略微调整,将if改为while。因为先序遍历能够保证为深度比当前节点浅的所有节点都创建相应的List。而中序/后序遍历会先走到最深的左/右子树,我们必须使用循环为所有层级比当前浅的节点创建对应的List。 DFS理论上会比BFS慢一些,因为存在函数调用与调用栈创建等开销。此外,如果树的层级过高,会有“爆栈”的风险。时间复杂度O(n),空间复杂度O(n)。全部代码如下:

Read more

127. 单词接龙

题目描述 给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则: 每次转换只能改变一个字母。 转换过程中的中间单词必须是字典中的单词。 说明: 如果不存在这样的转换序列,返回 0。 所有单词具有相同的长度。 所有单词只由小写字母组成。 字典中不存在重复的单词。 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。 示例 1: 输入: beginWord = “hit”, endWord = “cog”, wordList = [“hot”,”dot”,”dog”,”lot”,”log”,”cog”] 输出: 5 解释: 一个最短转换序列是 “hit” -> “hot” -> “dot” -> “dog” -> “cog”, 返回它的长度 5。 示例 2: 输入: beginWord = “hit” endWord = “cog” wordList = [“hot”,”dot”,”dog”,”lot”,”log”] 输出: 0 解释: endWord “cog” 不在字典中,所以无法进行转换。 https://leetcode-cn.com/problems/word-ladder/ 解法1…

Read more