经典算法-二叉树(golang)
package main func main() { } //Definition for a binary tree node. type TreeNode struct { Val int Left *TreeNode Right *TreeNode } // 938. Range Sum of BST 二叉搜索树的范围和 //Input: root = [10,5,15,3,7,null,18], L = 7, R = 15 Output: 32 //Input: root = [10,5,15,3,7,13,18,1,null,6], L = 6, R = 10 Output: 23 func rangeSumBST(root *TreeNode, L int, R int) int { if root == nil { return 0 } if root.Val > R { return rangeSumBST(root.Left, L, R) } if root.Val < L { return rangeSumBST(root.Right, L, R) } return root.Val + rangeSumBST(root.Left, L, R) + rangeSumBST(root.Right, L, R) } // 617. Merge Two Binary Trees 合并二叉树 //Input: // Tree 1 Tree 2 // 1 2 // / \ / \ // 3 2 1 3 // / \ \ // 5 4 7 //Output: // Merged tree: // 3 // / \ // 4 5 // / \ \ // 5 4 7 func mergeTrees(t1 *TreeNode, t2 *TreeNode) *TreeNode { if t1 == nil { // 如果t1为空,t2非空,那么我们就以t2的结点值建立一个新结点 return t2 } if t2 == nil { // 如果t2为空,t1非空,那么我们就以t1的结点值建立一个新结点 return t1 } // 如果t1和t2都非空,那么我们就以t1和t2的结点值之和建立一个新结点,然后分别对t1的左右子结点和t2的左右子结点调用递归函数 return &TreeNode{t1.Val + t2.Val, mergeTrees(t1.Left, t2.Left), mergeTrees(t1.Right, t2.Right)} } // 104. Maximum Depth of Binary Tree 求二叉树最大深度 // 思路:很简单,当前结点深度等于左右子树中较大的那个深度加一。 func maxDepth(root *TreeNode) int { if root == nil { return 0 } left := maxDepth(root.Left) right := maxDepth(root.Right) if left > right { return left + 1 } else { return right + 1 } }
//求二叉树最小深度 //算法参照二叉树的最大深度,这里需要注意的是当某节点的左右孩子都存在时,就返回左右子树的最小深度; //如果不都存在,就需要返回左右子树的最大深度(因为子节点不存在的话,通向该子树的路径就走不同,就不存在深度,也无法比较。 //只能从另一子树方向走。)如果左右孩子不都存在时还取小值,那返回的就是父节点的深度,会出错。 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 right + 1 } else { return left + 1 } }
// 226. Invert Binary Tree 反转二叉树 // 思路:递归互换左右子节点 //Example: // //Input: Output: // // 4 4 // / \ / \ // 2 7 7 2 // / \ / \ / \ / \ // 1 3 6 9 9 6 3 1 func invertTree(root *TreeNode) *TreeNode { if root == nil { return root } root.Left, root.Right = invertTree(root.Right), invertTree(root.Left) return root }
定义: 1,5节点的最近公共祖先是3;其实就是找1<x<5
// TODO 判断两棵树是否相等 func isEqual(r1, r2 *TreeNode) bool { if r1 == nil && r2 == nil { return true } if r1 == nil || r2 == nil { return false } if r1.Val == r2.Val { return isEqual(r1.Left, r2.Left) && isEqual(r1.Right, r2.Right) } return false }
// 538. Convert BST to Greater Tree 二叉查找树转化为更大树 // 思路:二叉查找树右边子节点比节点数值大,递归所有右节点的累加和 右-中-左遍歷相加 func convertBST(root *TreeNode) *TreeNode { node, _ := traverse(root, 0) return node } func traverse(root *TreeNode, sum int) (*TreeNode, int) { if root == nil { return nil, sum } _, sum = traverse(root.Right, sum) root.Val += sum sum = root.Val _, sum = traverse(root.Left, sum) return root, sum }
// 230.给定一个二叉搜索树,请找出其中第k小的节点。 // 中序遍历 func kthSmallest(root *TreeNode, k int) int { if root == nil { return 0 } var sum, num int var inOrder func(root *TreeNode) inOrder = func(root *TreeNode) { if root == nil { return } inOrder(root.Left) num++ if num == k { sum = root.Val return } inOrder(root.Right) } inOrder(root) return sum } // 给定一棵二叉搜索树,请找出其中第k大的节点。 // 中序遍历反着来:后-中-左 func kthLargest(root *TreeNode, k int) int { var num, sum int var inOrder func(root *TreeNode) inOrder = func(root *TreeNode) { if root == nil { return } inOrder(root.Right) num++ if num == k { sum = root.Val return } inOrder(root.Left) } inOrder(root) return sum }
// 98. 给定一个二叉树,判断其是否是一个有效的二叉搜索树。 // 中序遍历 var lastNode *TreeNode func isValidBST(root *TreeNode) bool { lastNode = nil return inOrder(root) } func inOrder(root *TreeNode) bool { if root == nil { return true } if !inOrder(root.Left) { return false } if lastNode != nil && lastNode.Val >= root.Val { return false } lastNode = root return inOrder(root.Right) } // 55. 给定一个二叉树,判断该树是不是平衡二叉树 func isBalanced(root *TreeNode) bool { if root == nil { return true } if maxDepth(root.Left) - maxDepth(root.Right) > 1 || maxDepth(root.Right) - maxDepth(root.Left) > 1 { return false } return isBalanced(root.Left) && isBalanced(root.Right) } func maxDepth(root *TreeNode) int { if root == nil { return 0 } left, right := maxDepth(root.Left), maxDepth(root.Right) if left > right { return left + 1 } return right + 1 }
// 从上到下按层打印二叉树 //例如: //给定二叉树: [3,9,20,null,null,15,7], // 3 // / \ // 9 20 // / \ // 15 7 //返回其层次遍历结果: // //[ //[3], //[9,20], //[15,7] //] func levelOrder(root *TreeNode) [][]int { if root == nil { return nil } var arr [][]int q := []*TreeNode{root} for len(q) > 0 { temp := make([]int, len(q)) length := len(q) for ; length >= 0; length-- { if q[0].Left != nil { q = append(q, q[0].Left) } if q[0].Right != nil { q = append(q, q[0].Right) } temp = append(temp, q[0].Val) q = q[1:] } arr = append(arr, temp) } return arr }
// 按照之字形打印二叉树 // 第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,依次类推 func printTreeNode(root *TreeNode) [][]int { if root == nil { return nil } var arr [][]int q := []*TreeNode{root} for level := 1; len(q) > 0; level++ { length := len(q) temp := make([]int, length) if level&0x1 == 1 { // 奇数层,顺序写入 for i := 0; i < length; i++ { temp = append(temp, q[i].Val) } } else { // 偶数层,倒着写入 for i := length-1; i >= 0; i-- { temp = append(temp, q[i].Val) } } arr = append(arr, temp)
// 为什么要从这里才开始处理q里面的节点呢, 是因为倒着写,会导致顺序出错,所以先处理完temp再处理q for ; length >= 0; length-- { if q[0].Left != nil { q = append(q, q[0].Left) } if q[0].Right != nil { q = append(q, q[0].Right) } q = q[1:] } } return arr }
// 向二叉搜索树插入元素 func insertTree(root *TreeNode, value int) { if root == nil { root = &TreeNode{value, nil, nil} } if value > root.Val { insertTree(root.Right, value) } else { insertTree(root.Left, value) } } // 从小到大输出值 var sortlist []int func inOrderTree(root *TreeNode) { if root == nil { return } inOrderTree(root.Left) sortlist = append(sortlist, root.Val) inOrderTree(root.Right) } // 查找最小值 func findTreeMin(root *TreeNode) int { //if root == nil { // return 0 //} //if root.Left != nil { // findTreeMin(root.Left) //} else { // return root.Val //} node := root for { if node.Left != nil { node = node.Left } else { return node.Val } } } // 查找某个值 func findTreeVal(root *TreeNode, value int) bool { node := root for { if node == nil { return false } else if value == node.Val { return true } else if value > node.Val { node = node.Right } else { node = node.Left } } }
// 二叉搜索树的最近公共祖先 func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode { for root != nil { if root.Val > p.Val && root.Val > q.Val { root = root.Left } else if root.Val < p.Val && root.Val < q.Val { root = root.Right } else { return root } } return root } // 二叉树的最近公共祖先 func lowestCommonAncestor(root *TreeNode, p *TreeNode, q *TreeNode) *TreeNode { if root == nil || root == p || root == q { return root } left := lowestCommonAncestor(root.Left, p, q) right := lowestCommonAncestor(root.Right, p, q) if left == nil { return right } if right == nil { return left } return root }
// 前序遍历 preorder = [3,9,20,15,7] // 中序遍历 inorder = [9,3,15,20,7] // // 返回如下的二叉树: // // 3 // / \ // 9 20 // / \ // 15 7 func buildTree(preorder []int, inorder []int) *TreeNode { if len(preorder) == 0 { return nil } first, index := preorder[0], 0 // 先找出preorder的根节点 for k, v := range inorder { if v == first { index = k // 找到根节点在inorder里面的左右部分left, right break } } root := &TreeNode{first, nil, nil} root.Left = buildTree(preorder[1:index+1], inorder[:index]) // preorder找左区域,inorder也找左区域 root.Right = buildTree(preorder[index+1:], inorder[index+1:]) // preorder找右区域,inorder也找右区域 return root }
// 将一个排序数组生成二叉排序树 data := []int{1, 2, 3, 4, 5, 6, 7, 8, 9} tree := buildSearchTree(data, 0, len(data)-1) func buildSearchTree(data []int, left, right int) *treeNode { if left > right { return nil } mid := left + (right-left)>>1 node := &treeNode{data[mid], nil, nil} node.Left = buildSearchTree(data, left, mid-1) node.Right = buildSearchTree(data, mid+1, right) return node }
// dfs: 二叉树:根节点到叶子节点的路径和为某一值 // 示例: //给定如下二叉树,以及目标和 sum = 22, // // 5 // / \ // 4 8 // / / \ // 11 13 4 // / \ / \ // 7 2 5 1 // // // 返回: // // [ // [5,4,11,2], // [5,8,4,5] //] func pathSum(root *TreeNode, sum int) [][]int { var arrlist [][]int var arr []int var dfs func(*TreeNode, int) dfs = func(root *TreeNode, sum int) { if root == nil { return } arr = append(arr, root.val) if root.val == sum && root.left == nil && root.right == nil { temp := make([]int, len(arr)) copy(temp, arr) arrlist = append(arrlist, temp) } dfs(root.left, sum-root.val) dfs(root.right, sum-root.val) arr = arr[:len(arr)-1] } dfs(root, sum) return arrlist } // 变种:假如求的是根节点到叶子节点的路径和为最大值 func pathMax(root *TreeNode) int { var pathList []int sum := 0 var dfs func(*TreeNode) dfs = func(root *TreeNode) { if root == nil { return } sum += root.val if root.left == nil && root.right == nil { pathList = append(pathList, sum) } dfs(root.left) dfs(root.right) sum -= root.val } dfs(root) maxnum := pathList[0] for _, v := range pathList { if v > maxnum { maxnum = v } } return maxnum }
// 二叉树中的最大路径和:这个路径的开始节点和结束节点可以是二叉树中的任意节点 func maxPathSum( root *TreeNode ) int { // write code here maxNum := root.Val var dfs func(*TreeNode) int dfs = func(root *TreeNode) int { if root == nil { return 0 } leftNum := max(dfs(root.Left), 0) // 如果小于0,加进去总值肯定变小,所以不要加入负数 rightNum := max(dfs(root.Right), 0) maxNum = max(maxNum, leftNum + rightNum + root.Val) return max(leftNum, rightNum) + root.Val // 只需要拿左边或右边的最大值 加上 当前值就行了,小值被淘汰 } dfs(root) return maxNum }
// 给定一个二叉树,确定它是否是一个完全二叉树(bfs搜索,必须是按顺序的,如果中间有一个为null,就不成立) func isCompleteTree(root *TreeNode) bool { if root == nil { return false } q := []*TreeNode{root} last := false // 记录上一个节点 for len(q) > 0 { node := q[0] q = q[1:] if node == nil { last = true } else { if last { // 只要之前有一个节点为空,那就不是完全二叉树了 return false } else { q = append(q, node.Left) q = append(q, node.Right) } } } return true }