在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
1、 需要记忆的部分: 分治法的基本思想是将一个规模为n 的问题分解为k 个规模较小的子问题,这些子问题互相独立且与原问题相同。递归的解这些子问题,然后将各子问题的解合并得到原问题的解。 对于二叉树问题,首先需要熟练记住二叉树的前序中序遍历的递归版本和迭代版本,后序也可以看一下,记住BFS的实现过程,归并排序,快速排序,二叉搜索树BST。 完全二叉树:左右节点高度差不能超过1; 二叉搜索树:root左边的节点都小于root,root右边的节点都大于root的值。判断标准是:中序遍历是一个增序列。 AVL平衡二叉树:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。 总结: 1)二叉树问题基本都是考察递归,几乎所有的二叉树问题时间复杂度都是O(N),空间复杂度和二叉树的高度有关系,因为每一次递归都需要系统内存开一个栈空间进行存储, 2)其中递归函数中使用void的函数是遍历版本,使用有返回值的函数是分治版本,使用全局变量会影响多线程, 3)helper函数是在递归中使用的,因为原有的函数可能只返回一个值,而中间的递归过程需要返回多个值,此时就需要再写一个helper函数 4)在求最大值问题时候,非法情况需要些root = NULL,此时返回一个负无穷大; 再求最小值问题的时候,此时返回一个正无穷大。 写分治自己的感悟是,先想想最简单的情况是怎么写的。
二叉树问题思考过程:首先r思考递归基的情况root ==NULL,return; 然后思考左右子树递归完有什么实际意义,然后分别进行处理; 2、下面是二叉树问题的模板: 1)遍历形式的模板;
Template 1: Traverse
2)divide and conquer模板
View Code
注意:this是指针,谁调用struct新建变量,this就指向这个变量,它是个指针记住,所以使用->; struct 后面接变量不加括号,最后需要加分号;,初始化方法有三种,列表初始化1,自己构造的不能使用new,再新建变量。 struct resultType{
int singlePath;
int maxPath;
// 1=> resultType(int x,int y):singlePath(x),maxPath(y){ }
// 2 => resultType(int x,int y){
// singlePath = x;
// maxPath = y;
// }
resultType(int x,int y){
this -> singlePath = x;
this -> maxPath = y;
}
};
使用new的时候必须要记得,在自由分配的内存是无名的,因此new无法为其分配的对象命名,而是返回一个指向该对象的指针,所以new的时候,前面必须是指针。 resultType* result = new resultType(0,INT_MIN);//必须要加* 3、二叉树分治法题目 深度优先搜索DFS: 3.1 Lowest Common Ancestor https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/#/description 思路:需要注意接口给出的变量里面必须要有root或者parent,不然该题没法做, 1)有parent的题目,首先遍历得到两个节点的父亲节点,存在两个vector或者list中,然后分别进行遍历比较,寻找第一个不同的节点,就是所求。 2)有root的题目,使用上述模板,注意分析,该节点是root就可以直接返回,a和b节点在左右子树,则返回root,只有一个节点在二叉树中,则直接返回该节点,都不在二叉树中,则返回NULL。 注意递归基的时候,只有某个节点等于root节点,那么就已经直接返回这个节点,自己也是自己的祖先。
/** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode { if root == nil || root == p || root == q{ return root } lTree := lowestCommonAncestor(root.Left, p, q) rTree := lowestCommonAncestor(root.Right, p, q) if lTree != nil && rTree != nil { return root } if lTree != nil { return lTree } if rTree != nil { return rTree } return nil } 235. Lowest Common Ancestor of a Binary Search Tree https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/description/ 使用递归可以轻松解决此问题。对于此题我们可以分为三种情况讨论: 1. P, Q都比root小,则LCA在左树,我们继续在左树中寻找LCA 2. P, Q都比root大,则LCA在右树,我们继续在右树中寻找LCA 3. 其它情况,表示P,Q在root两边,或者二者其一是root,或者都是root,这些情况表示root就是LCA,直接返回root即可。 /** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode { if root == nil || root == p || root == q { return root } if p.Val < root.Val && q.Val < root.Val { return lowestCommonAncestor(root.Left, p, q) } else if p.Val > root.Val && q.Val > root.Val { return lowestCommonAncestor(root.Right, p, q) } else { return root } }
3.2 Maximum Depth of Binary Tree https://leetcode.com/problems/maximum-depth-of-binary-tree/#/description Given the root of a binary tree, return its maximum depth. A binary tree's maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.
思路:递归到左右子树计算,看哪边深度大,关键理解最后一步每次返回到上一层都需要将深度增一。 根结点的深度是约定的,这道题目约定的是根节点的深度是1;根结点的深度是1,属于第1层。经过多少条边,深度就是多少。 /** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ func maxDepth(root *TreeNode) int { if root == nil { return 0 } left := maxDepth(root.Left) right := maxDepth(root.Right) if left > right { return left + 1 } return right + 1 }
111. Minimum Depth of Binary Tree https://leetcode.com/problems/minimum-depth-of-binary-tree/description/ 这道题是树的题目,其实跟Maximum Depth of Binary Tree非常类似,只是这道题因为是判断最小深度,所以必须增加一个叶子的判断(因为如果一个节点如果只有左子树或者右子树,我们不能取它左右子树中小的作为深度,因为那样会是0,我们只有在叶子节点才能判断深度,而在求最大深度的时候,因为一定会取大的那个,所以不会有这个问题)。这道题同样是递归和非递归的解法,递归解法比较常规的思路,比Maximum Depth of Binary Tree多加一个左右子树的判断. /** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ func minDepth(root *TreeNode) int { if root == nil { return 0 } if root.Left == nil { return minDepth(root.Right) + 1 } if root.Right == nil { return minDepth(root.Left) + 1 } return min(minDepth(root.Left), minDepth(root.Right)) + 1 } func min(a, b int) int { if a < b { return a } return b }
3.3 Balanced Binary Tree https://leetcode.com/problems/balanced-binary-tree/#/description 思路:基于二叉树最大深度那题,当左右子树深度大于1的时候深度返回-1这步是关键 /** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ func maxDepth(root *TreeNode) int { if root == nil { return 0 } //不平衡的时候用-1表示 left := maxDepth(root.Left) right := maxDepth(root.Right) if left == -1 || right == -1 || abs(left - right) > 1 { return -1 } return max(left, right) + 1 } func max(a, b int) int { if a < b { return b } return a } func abs(c int) int { if c < 0 { return -c } return c } func isBalanced(root *TreeNode) bool { if root == nil { return true } return maxDepth(root) != -1 }
4 宽度优先搜搜BFS 4,.1 Binary Tree Level Order Traversal (*) https://leetcode.com/problems/binary-tree-level-order-traversal/#/description Given the root of a binary tree, return the level order traversal of its nodes' values. (i.e., from left to right, level by level).
思路:二叉树的层次遍历就是宽度优先搜索,总共有三种实现方式, - 2 Queues(一个存parent,一个存儿子节点,每次都需要清空一个queue) 这里需要注意,首先将root节点入栈,接下来是双循环,外层是队列不为空,内层是遍历每一层,进入内层循环之前要使用一个int记录队列的大小,代表该层节点个数。 /** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ func levelOrder(root *TreeNode) [][]int { if root == nil { return [][]int{} } queue := []*TreeNode{root} res := [][]int{} for len(queue) != 0 { curRes := []int{} newQueue := []*TreeNode{} for _, node := range queue { curRes = append(curRes, node.Val) if node.Left != nil { newQueue = append(newQueue, node.Left) } if node.Right != nil { newQueue = append(newQueue, node.Right) } } res = append(res, curRes) queue = newQueue } return res }
5 二叉搜索树 Binary Search Tree 5.1 Validate Binary Search Tree https://leetcode.com/problems/validate-binary-search-tree/#/description Given the A valid BST is defined as follows:
思路:验证是否是二叉搜索树,使用中序遍历,如果是递增序列,那么就是二叉搜索树。平衡二叉树:root为空也是二叉搜索树,每个元素不相等,左边小于root,右边大于root; 切片的传递,&arr,这样才能修改切片的值,引用类型指的是引用底层的数组。 /** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ func helper(root *TreeNode, res *[]int) { if root != nil { helper(root.Left, res) *res = append(*res, root.Val) helper(root.Right, res) } } func isValidBST(root *TreeNode) bool { if root == nil { return true } res := []int{} helper(root, &res) for i:= 0; i < len(res) - 1;i++ { if res[i] >= res[i + 1] { return false } } return true }
5.2 Insert Node in a Binary Search Tree http://www.lintcode.com/en/problem/insert-node-in-a-binary-search-tree/ 思路:记住需要插入的节点一定是在二叉树某个叶子节点下面插入的(这里是理解重点),就是递归到递归基的时候,还有就是记得左右递归的if条件。
insert Node
5.3 Search Range in Binary Search Tree http://www.lintcode.com/en/problem/search-range-in-binary-search-tree/ 思路:注意递归的时候如果比k1大,就进入左子树,如果比k2小,就进行右子树。在两者之间,就压入result数组。
search Range
6.124. Binary Tree Maximum Path Sum https://leetcode.com/problems/binary-tree-maximum-path-sum/#/description 思路:先思考一个简化版的情况,然后再思考该题。该题最大路径和可能在左子树,可能在右子树,可能是左子树的节点经过root然后到右子树的节点。 root等于空的时候是非法情况,求最大就需要返回最小,求最小就需要返回最大值。自己定义一个struct,里面包含两个值,一个是简化版的single path,一个是该题的max path。。 接下来进行分治,首先分:想左子树右子树递归完分别希望得到什么结果,接下来治:分别求出single path 和max path。
使用new的版本
maxPath
7.129. Sum Root to Leaf Numbers https://leetcode.com/problems/sum-root-to-leaf-numbers/#/description You are given the Each root-to-leaf path in the tree represents a number.
Return the total sum of all root-to-leaf numbers. A leaf node is a node with no children. The root-to-leaf path Return the sum = 12 + 13 = 思路:这题还是不怎么理解,采用的是自顶向下的递归设计,所以sum = 目前值加上10倍前面的值,最后返回的时候需要将左右子树的值相加放回。因为每次都需要将sum传递给下一个递归函数,所以首先对sum进行计算,已经到达叶子节点则该路径的值以及计算出来,需要将值返回,不是叶子结点的话,就需要将左右子树的值加起来返回。 func sumNumbers(root *TreeNode) int { sum := 0 var s func(*TreeNode, int) s = func(root *TreeNode, total int) { if root == nil {return} if root.Left == nil && root.Right == nil { sum += (total * 10) + root.Val return } total = ((total * 10) + root.Val) s(root.Left, total) s(root.Right, total) } s(root, 0) return sum }
8.112. Path Sum https://leetcode.com/problems/path-sum/#/description 是否存在一条路径等于指定的sum /** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ func hasPathSum(root *TreeNode, targetSum int) bool { if root == nil { return false } if root.Left == nil && root.Right == nil { return root.Val == targetSum } return hasPathSum(root.Left, targetSum - root.Val) || hasPathSum(root.Right, targetSum - root.Val) } 9.173. Binary Search Tree Iterator https://leetcode.com/problems/binary-search-tree-iterator/#/description Implement an iterator over a binary search tree (BST). Your iterator will be initialized with the root node of a BST. Calling Note: 思路:其实就是中序遍历迭代版,这题要看清题目,是二叉搜索树,左<中<右;遍历到最左边就是最小的元素。 https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/er-cha-shu-de-zhong-xu-bian-li-by-leetcode-solutio/ type BSTIterator struct { stack []*TreeNode cur *TreeNode } func Constructor(root *TreeNode) BSTIterator { return BSTIterator{cur: root} } func (it *BSTIterator) Next() int { for node := it.cur; node != nil; node = node.Left { it.stack = append(it.stack, node) } it.cur, it.stack = it.stack[len(it.stack)-1], it.stack[:len(it.stack)-1] val := it.cur.Val it.cur = it.cur.Right return val } func (it *BSTIterator) HasNext() bool { return it.cur != nil || len(it.stack) > 0 }
|
请发表评论