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 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
一棵二叉树要么是空树,要么有一个或两个指针,指针指向一棵树,
用递归实现很简单, 当指针为空,即是递归出口,返回0, 求最大深度就是左右子树选出一个最大值。
代码
func maxDepth(root *TreeNode) int { if root == nil { return 0 } return int(math.Max(float64(maxDepth(root.Left)), float64(maxDepth(root.Right)))) + 1 }
110. 平衡二叉树
题目
给定一个二叉树,判断它是否是高度平衡的二叉树。 本题中,一棵高度平衡二叉树定义为: 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。 示例 1: 给定二叉树 [3,9,20,null,null,15,7] 3 / \ 9 20 / \ 15 7 返回 true 。 示例 2: 给定二叉树 [1,2,2,3,3,null,null,4,4] 1 / \ 2 2 / \ 3 3 / \ 4 4 返回 false 。 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/balanced-binary-tree 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
首先知道二叉平衡树的性质,其是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
分两步走:
- 首先求左右子树的高度
- 判断左右子树的差值是否符合要求
代码
// 求二叉树的高度 func Height(node *TreeNode) (h int) { if node == nil { return 0 } left := Height(node.Left) right := Height(node.Right) if left > right { return left + 1 } else { return right + 1 } } // 判断是否为二叉平衡树 func isBalanced(root *TreeNode) bool { if root == nil { return true } diff := Height(root.Left) - Height(root.Right) if diff < -1 || diff > 1 { return false } if isBalanced(root.Left) && isBalanced(root.Right) { return true } return false }
543. 二叉树的直径
题目
给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过根结点。 示例 : 给定二叉树 1 / \ 2 3 / \ 4 5 返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。 注意:两结点之间的路径长度是以它们之间边的数目表示 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/diameter-of-binary-tree 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
- 二叉树的直径等于从一个结点到另一个结点的最大长度,也就是左子树的最大深度+右子树的最大深度+1。
- 采用分治法和递归进行求解。
代码
var max int = 0 func diameterOfBinaryTree(root *TreeNode) int { max = 0 // 运行样例前需要重置为0 Depth(root) return max } // 最长路径 func Depth(node *TreeNode) int { if node == nil { return 0 } left := Depth(node.Left) right := Depth(node.Right) if left + right > max { max = left + right } if left > right { return left + 1 } else { return right + 1 } }
226.翻转二叉树
题目
翻转一棵二叉树。 示例: 输入: 4 / \ 2 7 / \ / \ 1 3 6 9 输出: 4 / \ 7 2 / \ / \ 9 6 3 1 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/invert-binary-tree 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
二叉树的翻转,其实就是递归的将左右子树进行调换。
代码
// 翻转二叉树 func invertTree(root *TreeNode) *TreeNode { if root == nil { return nil } // go语言特性交换值 root.Left, root.Right = root.Right, root.Left invertTree(root.Left) invertTree(root.Right) return root }
617.合并二叉树
题目
给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。 你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。 示例 1: 输入: Tree 1 Tree 2 1 2 / \ / \ 3 2 1 3 / \ \ 5 4 7 输出: 合并后的树: 3 / \ 4 5 / \ \ 5 4 7 注意: 合并必须从两个树的根节点开始。 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/merge-two-binary-trees 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
递归合并即可, 当两棵树都为空时即是递归出口,其中一棵树为空则用另一颗树填充,均不为空则将值相加作为新节点。
代码
// 合并二叉树 func mergeTrees(t1 *TreeNode, t2 *TreeNode) *TreeNode { if t1 == nil && t2 == nil { return nil } if t1 == nil { return t2 } if t2 == nil { return t1 } root := new(TreeNode) root.Val = t1.Val + t2.Val root.Left = mergeTrees(t1.Left, t2.Left) // 合并左子树 root.Right = mergeTrees(t1.Right, t2.Right) // 合并右子树 return root }
112.路径总和
题目
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。 说明: 叶子节点是指没有子节点的节点。 示例: 给定如下二叉树,以及目标和 sum = 22, 5 / \ 4 8 / / \ 11 13 4 / \ \ 7 2 1 返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/path-sum 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
使用目标值一步进行递减, 每个结点都有两条路径可走,判断结点没有左右子结点时该结点即为终止结点,只需判断最终值是否跟sum的剩余值相等即可。
代码
// 判断路径和是否等于一个数 func hasPathSum(root *TreeNode, sum int) bool { if root == nil { return false } if root.Left == nil && root.Right == nil && root.Val == sum { return true } return hasPathSum(root.Left, sum - root.Val) || hasPathSum(root.Right, sum - root.Val) }
116. 路径总和III
题目
给定一个二叉树,它的每个结点都存放着一个整数值。 找出路径和等于给定数值的路径总数。 路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。 二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。 示例: root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8 10 / \ 5 -3 / \ \ 3 2 11 / \ \ 3 -2 1 返回 3。和等于 8 的路径有: 1. 5 -> 3 2. 5 -> 2 -> 1 3. -3 -> 11 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/path-sum-iii 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
进行双重递归, 根结点向下遍历, 根的左右结点再进行向下遍历。
代码
func pathSum(root *TreeNode, sum int) int { if root == nil{ return 0 } return pathSumRecursion(root, sum, 0) + pathSum(root.Left, sum) + pathSum(root.Right, sum) } func pathSumRecursion(root *TreeNode, sum int, count int)int{ if root == nil { return count } sum -= root.Val if sum == 0{ count++ } count = pathSumRecursion(root.Left, sum, count) count = pathSumRecursion(root.Right, sum, count) return count }
572.另一个树的子树
题目
给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和节点值的子树。s 的一个子树包括 s 的一个节点和这个节点的所有子孙。s 也可以看做它自身的一棵子树。 示例 1: 给定的树 s: 3 / \ 4 5 / \ 1 2 给定的树 t: 4 / \ 1 2 返回 true,因为 t 与 s 的一个子树拥有相同的结构和节点值。 示例 2: 给定的树 s: 3 / \ 4 5 / \ 1 2 / 0 给定的树 t: 4 / \ 1 2 返回 false。 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/subtree-of-another-tree 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
检测s中是否包含子树t,s自身拆分成多个树,与树t进行比较是否相等。
代码
// 判断是否有子树 func isSubtree(s *TreeNode, t *TreeNode) bool { if s == nil { return false } return isSame(s, t) || isSubtree(s.Left, t) || isSubtree(s.Right, t) } // 判断两树是否相同 func isSame(s *TreeNode, t *TreeNode) bool { if s == nil && t == nil { return true } if s == nil || t == nil { return false } return s.Val == t.Val && isSame(s.Left, t.Left) && isSame(s.Right, t.Right) }
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 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/symmetric-tree 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
判断是否为对称二叉树, 跟判断两个树是否相同差不多, 只不过是将二叉树1的左子树跟二叉树2的右子树进行比较。
代码
// 判断是否为镜像树 func isSymmetric(root *TreeNode) bool { if root == nil { return true } return isSmt(root.Left, root.Right) } // 判断是否为镜像树 func isSmt(t1 *TreeNode, t2 *TreeNode) bool { if t1 == nil && t2 == nil { return true } if t1 == nil || t2 == nil { return false } // t1的左子树跟t2的右子树进行对比 return (t1.Val == t2.Val) && isSmt(t1.Left, t2.Right) && isSmt(t1.Right, t2.Left) }
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 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
思想跟求二叉树的最大深度类似, 区别在于数值的比较。
代码
func minDepth(root *TreeNode) int { if root == nil { return 0 } left := minDepth(root.Left) right := minDepth(root.Right) if left == 0 || right == 0 { return left + right + 1 } if left < right { return left + 1 }else { return right + 1 } }
404.左叶子之和
题目
计算给定二叉树的所有左叶子之和。 示例: 3 / \ 9 20 / \ 15 7 在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/sum-of-left-leaves 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
递归遍历结点,只添加左叶子结点的值。
代码
func sumOfLeftLeaves(root *TreeNode) int { if root == nil { return 0 } if isLeaf(root.Left) { // 剪枝 return root.Left.Val + sumOfLeftLeaves(root.Right); } return sumOfLeftLeaves(root.Left) + sumOfLeftLeaves(root.Right) } // 判断结点是否有子节点, 用于剪枝 func isLeaf(node *TreeNode) bool { if node == nil { return false } return node.Left == nil && node.Right == nil }
337.打家劫舍III
题目
在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。 计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。 示例 1: 输入: [3,2,3,null,3,null,1] 3 / \ 2 3 \ \ 3 1 输出: 7 解释: 小偷一晚能够盗取的最高金额 = 3 + 3 + 1 = 7. 示例 2: 输入: [3,4,5,1,3,null,1] 3 / \ 4 5 / \ \ 1 3 1 输出: 9 解释: 小偷一晚能够盗取的最高金额 = 4 + 5 = 9. 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/house-robber-iii 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
其实就是间隔遍历节点, 可分为两种情况递归求解:
- 打劫根节点,那么就不能打劫左右子树了,要打劫子孙辈的所有节点。
- 不打劫根节点, 那么打劫左右子树。
- 判断两种情况的哪个价值高。
代码
// 间隔遍历 func rob(root *TreeNode) int { if root == nil { return 0 } val1 := root.Val // 打劫子孙辈节点 if root.Left != nil { val1 += rob(root.Left.Left) + rob(root.Left.Right) } if root.Right != nil { val1 += rob(root.Right.Left) + rob(root.Right.Right) } // 打劫左右子树 val2 := rob(root.Left) + rob(root.Right) if val1 > val2 { return val1 } return val2 }
671.二叉树中第二小节点
题目
给定一个非空特殊的二叉树,每个节点都是正数,并且每个节点的子节点数量只能为 2 或 0。如果一个节点有两个子节点的话,那么这个节点的值不大于它的子节点的值。 给出这样的一个二叉树,你需要输出所有节点中的第二小的值。如果第二小的值不存在的话,输出 -1 。 示例 1: 输入: 2 / \ 2 5 / \ 5 7 输出: 5 说明: 最小的值是 2 ,第二小的值是 5 。 示例 2: 输入: 2 / \ 2 2 输出: -1 说明: 最小的值是 2, 但是不存在第二小的值。 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/second-minimum-node-in-a-binary-tree 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
- 由题可知,二叉树的子节点大于或等于父节点, 如果相等的情况下,则需要继续往子节点查找,
否则进行左右节点的比较,返回较小的一个,如果其中一个节点为空,那么另一个节点即为要找的值。
代码
func findSecondMinimumValue(root *TreeNode) int { if root == nil { //根节点为空,找不到 return -1 } // 左右子树为空找不到 if root.Left == nil && root.Right == nil { return -1 } left := root.Left.Val right := root.Right.Val if left == root.Val { // 左子树与根节点值相同继续往下找 left = findSecondMinimumValue(root.Left) } if right == root.Val { // 右子树与根节点值相同继续往下找 right = findSecondMinimumValue(root.Right) } // 左右子树进行比较,返回值小的 if left != -1 && right != -1 { return min(left, right) } // 左子树不为空,则返回左子树,否则为右子树 if left != -1 { return left } return right } func min(a, b int) int { if a > b { return b } return a }