算法通关村——树的算法

迭代实现二叉树的遍历

144.二叉树的前序遍历

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        if(root == null) {
            return res;
        }
        //辅助栈
        Deque<TreeNode> stack = new LinkedList<TreeNode>();
        //
        TreeNode cur = root;

        while(!stack.isEmpty() || node != null) {
            //一路向左下处理
            while(node != null) {
                res.add(node.val);
                stack.push(node);
                node = node.left;
            }
            //当没有左孩子时,取出栈中的节点,向右孩子处理
            //下一次循环即为,处理右子树
            node = stack.pop();
            node = node.right;
        }
    }
}

94.二叉树的中序遍历

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        if(root == null) {
            return res;
        }
        //辅助栈
        Deque<TreeNode> stack = new LinkedList<TreeNode>();
        //
        TreeNode node = root;
        //首次进入循环,会出现stack为空的情况
        while(!stack.isEmpty() || node != null) {
            //一路向左下,不访问
            while(node != null) {
                stack.push(node);
                node = node.left;
            }
			//核心
            //如果节点没有右子树(node = node.right,之后由第一个循环进行判断)
            //说明以该节点作为根节点的树,已经遍历结束
            //会继续回溯
            node = stack.pop();
            res.add(node.val);
            node = node.right;
        }
        return res;
    }
}

145.二叉树的后序遍历

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        if(root == null) {
            return res;
        }
        //辅助栈
        Deque<TreeNode> stack = new LinkedList<TreeNode>();
        //
        TreeNode pre = root;
        while(!stack.isEmpty() || root != null) {
            while(root != null) {
                stack.push(root);
                root = root.left;
            }
            root = stack.pop();
            //当前没有左子树了,判断是处理右子树,还是处理当前节点
            //右子树已经遍历过的两种情况:
            //没有右子树
            //右子树刚刚被遍历
            if(root.right == null || pre == root.right) {
                //访问节点
                res.add(root.val);
                //记录上一个访问的节点
                pre = root;
                //这里有个大坑
                //每次遍历完左子树
                //如果不做置空操作
                //则会重新入栈左子树
                root = null;
            } else {
                //处理右子树
                //将当前节点入栈
                //root指向右子树根节点
                stack.push(root);
                root = root.right;
            }
        }
        return res;
    }
}

树的经典算法

100.相同的树

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        //若树为空则相同
        if(p == null && q == null) {
            return true;
        }
        //若任意一个为空则不相同
        if(p == null || q == null) {
            return false;
        }
        //值不相同则不相同
        if(p.val != q.val) {
            return false;
        }

        //左右子树均相同
        return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
    }
}

101.对称树

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isSymmetric(TreeNode root) {
        if(root.left == null && root.right == null) return true;
        return isSymmetric1(root.left, root.right);

    }

    public boolean isSymmetric1(TreeNode q, TreeNode p) {
        //结构对称
        //均为空,则对称
        if(q == null && p == null) {
            return true;
        }
        //任一为空,则不对称
        if(q == null || p == null) {
            return false;
        }
        //数值对称
        //左孩子等于右孩子,则对称
        if(p.val != q.val) {
            return false;
        }

        return isSymmetric1(q.left, p.right) && isSymmetric1(q.right, p.left);
    }
}

617.合并树

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        if(root1 == null) {
            return root2;
        }
        if(root2 == null) {
            return root1;
        }
        TreeNode merged = new TreeNode(root1.val + root2.val);
        merged.left = mergeTrees(root1.left, root2.left);
        merged.right = mergeTrees(root1.right, root2.right);
        return merged;
    }
}

路径问题

257.二叉树的所有路径

递归算法

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<String> binaryTreePaths(TreeNode root) {
        List<String> res = new ArrayList<String>();
        dfs(root, "", res);
        return res;
    }
    void dfs(TreeNode root, String path, List<String> res) {
        if(root == null) return;
        //叶节点
        if(root.left == null && root.right == null) {
            res.add(path + root.val);
            return;
        }
        //路径的扩展,通过传参的方式
        dfs(root.left, path + root.val + "->", res);
        dfs(root.right, path + root.val + "->", res);
    }
}

迭代算法

回溯算法的入门,后续补充

112.路径总和

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean hasPathSum(TreeNode root, int sum) {
        if(root == null) {
            return false;
        }
        //进入根节点后,若 sum == root.val则为真
        if(root.left == null && root.right == null) {
            return sum == root.val;
        }
        boolean left = hasPathSum(root.left, sum - root.val);
        boolean right = hasPathSum(root.right, sum - root.val);
        return left || right;
    }

}

226.翻转二叉树

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public TreeNode invertTree(TreeNode root) {
        if(root == null) {
            return null;
        }
        
        if(root.left != null || root.right != null) {
            TreeNode tmp = root.left;
            root.left = root.right;
            root.right = tmp;
        }

        invertTree(root.left);
        invertTree(root.right);
        return root;
    }
}

深度问题

104.最大深度

递归

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public int maxDepth(TreeNode root) {
        //每层节点返回当前深度
        //还要有大小比较
        //应该要有一个参数来传递当前的深度
        return getMaxDepth(root, 1);
        
    }
    
    //depth为当前的深度
    public int getMaxDepth(TreeNode root, int depth) {
        //处理到空节点返回0
        if(root == null) {
            return 0;
        }
        //若处理到叶子节点,则返回当前深度
        if(root.left == null && root.right == null) {
            return depth;
        }
        //返回深度的最大值
        return getMax(getMaxDepth(root.left, depth + 1), getMaxDepth(root.right, depth + 1));
    }

    public int getMax(int a, int b) {
        return a > b ? a : b;
    }
}

还有更简洁的代码

public int maxDepth(TreeNode root) {
    if(root == null) {
        return 0;
    }
    int leftDepth = maxDepth(root.left);
    int rightDepth = maxDepth(root.right);
    return max(leftDepth, rightDepth) + 1;
}

迭代

本质是层次遍历,计算层数

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public int maxDepth(TreeNode root) {
        if(root == null) {
            return 0;
        }
        Deque<TreeNode> queue = new LinkedList<TreeNode>();
        queue.addLast(root);
        int ans = 0;
        while(!queue.isEmpty()) {
            //上一次循环中,获取的一层的节点数
            int size = queue.size();
            ans++;
            for(int i = 0; i < size; i++) {
                //出队
                TreeNode tmp = queue.pollFirst();
                //子节点入队
                if(tmp.left != null) {
                    queue.addLast(tmp.left);
                }
                
                if(tmp.right != null) {
                    queue.addLast(tmp.right);
                }
                
            }
        }
        return ans;
        
    }
}

110.判断平衡二叉树

我写了一段错误代码,分享出来

class Solution {
    public boolean isBalanced(TreeNode root) {
        //本质:左右子树最大深度之差是否小于1
        if(root == null) {
            return true;
        }
        int leftDepth = getMaxDepth(root.left);
        int rightDepth = getMaxDepth(root.right);
        int flag = Math.abs(leftDepth - rightDepth);
        return flag <= 1;
    }
    public int getMaxDepth(TreeNode root) {
        if(root == null) return 0;
        int leftDepth = getMaxDepth(root.left);
        int rightDepth = getMaxDepth(root.right);
        return Math.max(leftDepth, rightDepth) + 1;
    }
}

这段代码的逻辑问题在于,只判断了当前节点的左右子树的最大深度差是否小于等于1,但没有判断左右子树本身是否是平衡二叉树。

在判断平衡二叉树时,需要同时满足两个条件:

  1. 当前节点的左右子树高度差不超过1。
  2. 当前节点的左子树和右子树都是平衡二叉树。

以下是正确代码

class Solution {
    public boolean isBalanced(TreeNode root) {
        //本质:左右子树最大深度之差是否小于1,再判断左右子树也是平衡二叉树
        if(root == null) {
            return true;
        }
        int leftDepth = getMaxDepth(root.left);
        int rightDepth = getMaxDepth(root.right);
        int depthDiff  = Math.abs(leftDepth - rightDepth);
        if(depthDiff  > 1) return false;

        boolean leftBalanced = isBalanced(root.left);
        boolean rightBalanced = isBalanced(root.right);
        
        return leftBalanced && rightBalanced;
    }
    public int getMaxDepth(TreeNode root) {
        if(root == null) return 0;
        int leftDepth = getMaxDepth(root.left);
        int rightDepth = getMaxDepth(root.right);
        return Math.max(leftDepth, rightDepth) + 1;
    }
}

优化

上面的代码,在每个节点上都进行了重复的递归计算,可以通过对每个节点记录其高度的方式来避免重复计算。

class Solution {
    public boolean isBalanced(TreeNode root) {
        return checkHeight(root) != -1;
    }
    
    private int checkHeight(TreeNode root) {
        if (root == null) {
            return 0;
        }
        
        int leftHeight = checkHeight(root.left);
        if (leftHeight == -1) {
            return -1;
        }
        
        int rightHeight = checkHeight(root.right);
        if (rightHeight == -1) {
            return -1;
        }
        
        int heightDiff = Math.abs(leftHeight - rightHeight);
        if (heightDiff > 1) {
            return -1;
        }
        
        return Math.max(leftHeight, rightHeight) + 1;
    }
}

111.最小深度

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
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), min_depth);
        }
        if(root.right != null) {
            min_depth = Math.min(minDepth(root.right), min_depth);
        }

        return min_depth + 1;
    }
}

共同祖先

236.最近公共组选

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null || root == p || root == q) return root;
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);
        if(left == null && right == null) return null;
        if(left == null) return right;
        if(right == null) return left;
        return root;//if(left != null && right != null)
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值