通过二叉树去学习递归
递归其实就是一个自己调用自己的过程,起初自己在理解递归时总是企图去分析函数调用栈来理解递归的过程,一开始简单的递归函数还好分析,但遇到复杂的函数时候分析着分析着就乱套了。因此每次遇到复杂的递归函数总是令我头大,让我束手无策。后来通过写大量的简单的二叉树的题目让我对递归有了新的认识,在写递归时候不能总想着函数调用栈,这样会乱套,应该把重点放在函数的功能上,每一次的调用自己都在实现什么,是找叶节点还是某一个特殊的节点?递归总得有个结束自己的过程把,因此在函数在找到或者没有找到自己的目标时,得返回点什么(空对象还是别的),这就是递归的出口。在调用完自己得到结果还得返回一个值,这个值就是自己最终想要的答案。
如果就想分析一波函数调用的过程,我推荐从递归结束的地方逐步向上分析,如果一开始就从上向下分析,函数调用了自己,自己又调用了自己,然后再开始返回值,这样的过程很容易迷惑自己。从下向上分析过程比较清晰,可以由返回值直接跳到调用自己的地方。可以从二叉树的叶子节(也就是递归结束的地方)点往上考虑。
我目前比较喜欢的是想好递归的思路后先去写调用自身的地方,然后再去写递归出口和返回值。递归不是蒙出来的,思路很重要,思路清晰的话可以很顺利地把递归函数写出来,不然只会越写越乱。所以一开始一定要认真的分析题目,把各种条件、特殊情况都想好再动手写代码。
104.二叉树的最大深度
public Solution{
public int maxDepth(TreeNode root){
if(root == null)
return 0;
return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}
}
108.将有序数组转换为二叉搜索树
class Solution{
public TreeNode sortedArrayToBST(int[] nums){
return helper(nums, 0, nums.length-1);
}
public TreeNode helper(int[] nums, int left, int right){
if(left > right)
return null;
int mid = (left + right)/2;
TreeNode root = new TreeNode(nums[mid]);
root.left = helper(nums, left, mid - 1);
root.right = helper(nums, mid + 1, right);
return root;
}
}
剑指Offer 07.重建二叉树
class Solution{
private Map<Integer, Integer> indexMap;
public TreeNode buildTree(int[] preorder, int[] inorder){
int n = preorder.length;
indexMap = new HashMap<Integer, Integer>();
for(int i = 0; i < n; ++i)
indexMap.put(inorder[i], i);
return myBuildTree(preorder, inorder, 0, n-1, 0, n-1);
}
public TreeNode myBuildTree(int[] preorder, int[] inorder, int pre_left, int pre_right, int in_left, int in_right){
if(pre_left > pre_right)
return null;
int pre_root = pre_left; //前序遍历第一个节点就是根节点
int in_root = indexMap.get(preorder[pre_root]); //在中序遍历中定位根节点
TreeNode root = new TreeNode(preorder[pre_root]); //先构建根节点
int size_left_subtree = in_root - in_left; //得到左子树的节点数目
root.left = myBuildTree(preorder, inorder, pre_left + 1, pre_left + siez_left_subtree, in_left, in_root - 1);
root.right = myBuildTree(preorder, inorder, pre_left + size_left_subtree + 1, pre_right, in_root + 1, in_right);
return root;
}
}
404.左子叶之和
class Solution{
public int sumOfLeftLeaves(TreeNode root){
return root != null ? dfs(root) : 0;
}
public int dfs(TreeNode node){
int ans = 0;
if(node.left != null)
ans += isLeafNode(node.left) ? node.left.val : dfs(node.left);
if(node.right != null)
ans += dfs(node.right);
return ans;
}
public boolean isLeafNode(TreeNode node){
return node.left == null && node.right == null;
}
}
257.二叉树的所有路径
class Solution{
public List<String> binaryTreePaths(TreeNode root){
List<String> paths = new ArrayList<String>();
constructPaths(root, "", paths);
return paths;
}
public void constructPaths(TreeNode root, String path, List<String> paths){
if(root != null){
StringBuffer pathSB = new StringBuffer(path);
pathSB.append(Integer.toString(root.val));
if(root.left == null && root.right == null){
paths.add(pathSB.toString());
}else{
pathSB.append("->");
constructorPaths(root.left, pathSB.toString(), paths);
constructorPaths(root.right, pathSB.toString(), paths);
}
}
}
}
235.二叉搜索树的最近公共祖先
class Solution{
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q){
if((root.val-p.val) * (root.val-q.val) <= 0)
return root;
return lowestCommonAncestor(root.val < p.val ? root.right : root.left, p, q);
}
}
112.路径总和
class Solution{
public boolean hasPathSum(TreeNode root, int targetSum){
if(root == null)
return false;
if(root.left == null && root.right == null)
return 0 == targetSum - root.val;
return hasPathSum(root.left, targetSum-root.val) || hasPathSum(root.right, targetSum-root.val);
}
}
111.二叉树的最小深度
class Solution{
public int minDepth(TreeNode root){
if(root == null)
return 0;
if(root.left == null && root.right == null)
return 1;
int min_Depth = Integer.MAX_VALUE;
if(root.left != null)
min_Depth = Math.min(minDepth(root.left), minDepth);
if(root.right != null)
min_Depth = Math.min(minDepth(root.right), minDepth);
return min_Depth + 1;
}
-----------------------------------------------------------------
public int minDepth(TreeNode root){
if(root == null)
return 0;
int m1 = minDepth(root.left);
int m2 = minDepth(root.right);
return root.left == null || root.right == null ? m1 + m2 + 1 : Math.min(m1, m2) + 1;
}
}
110.平衡二叉树(剑指Offer 55)
自顶向下
class Solution{
public boolean isBalanced(TreeNode root){
if(root == null)
return true;
else
return Math.abs(height(root.left) - height(root.right)) <= 1 && isBalanced(root.left) && isBalanced(root.right);
}
public int height(TreeNode root){
if(root == null)
return 0;
return Math.max(height(root.left), height(root.right)) + 1;
}
}
自底向上
class Solution{
public boolean isBalanecd(TreeNode root){
return height(root) >= 0;
}
public int height(TreeNode root){
if(root == null)
return 0;
int leftHeight = height(root.left);
int rightHeight = height(root.right);
if(leftHeigt == -1 || rightHeight == -1 || Math.abs(leftHeihgt - rightHeight) > 1)
return -1;
else
return Math.max(leftHeight, rightHeight) + 1;
}
}
101.对称二叉树
class Solution{
public boolean isSymmetric(TreeNode root){
return check(root, root);
}
public boolean check(TreeNode p, TreeNode q){
//递归终止条件:两个节点都为空或者有一个为空或者两个节点值不相等
if(p == null && q == null)
return true;
if(p == null || q == null)
return false;
return q.val == p.val && check(p.left, q.right) && check(p.right, q.left);
}
}
100.相同的树
class Solution{
public boolean isSameTree(TreeNode p, TreeNode q){
if(p == null && q == null)
return true;
if(p == null || q == null)
return false;
return p.val == q.val && isSameTree(p.left, q. left) && isSameTree(p.right, q.right);
}
}
938. 二叉搜索树的范围和
class Solution{
public int rangeSumBST(TreeNode root, int low, int high){
if(root == null)
return 0;
if(root.val > hight)
return rangeSumBST(root.left, low, high);
if(root.val < low)
return rangeSumBST(root.right, low, high);
return root.val + rangeSumBST(root.left, low, high) + rangeSumBST(root.right, low, high);
}
}