赞
踩
继之前做完
的题目之后,我又做了LeetCode上关于树的题目:https://leetcode.com/tag/tree/
在做的过程中有些题没有思路,于是便看了 Discuss 或者《Cracking the coding Interview》和算法导论等书籍,下面从 Easy ~ Hard 给出答案:
这里二叉树的结构是:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
检查一个二叉树是否是平衡二叉树。平衡二叉树的定义是:任意一个节点的两个子树高度差不超过1。
根据定义,我们可以找出每个节点的左右子树的高度,再相减,大于1的话则不是平衡二叉树。我们在算高度的时候直接检查是否是平衡的,不是直接返回-1,是则返回这个树的高度。
public class Solution { public boolean isBalanced(TreeNode root) { if(checkHeight(root) == -1){ return false; } else { return true; } } private int checkHeight(TreeNode root){ if(root == null) return 0; int l = checkHeight(root.left); if(l == -1) return -1; int r = checkHeight(root.right); if(r == -1) return -1; if(Math.abs(l - r) > 1) return -1; else return Math.max(l, r) + 1; } }
打印所有根节点到叶子节点的路径
直接前序遍历,遇到叶子节点打印出来。
public class Solution {
public List<String> binaryTreePaths(TreeNode root) {
List<String> res = new ArrayList<>();
if(root != null) path(res, "", root);
return res;
}
private void path(List<String> res, String s, TreeNode root){
if(root.left == null && root.right == null) res.add(s + root.val);
if (root.left != null) path(res, s + root.val + "->", root.left);
if (root.right != null) path(res, s + root.val + "->", root.right);
}
}
二叉树层序遍历
思路:我们只需要遍历整棵树,在遍历的时候需要一个标志记住遍历到了第几层。
public class Solution { public List<List<Integer>> levelOrder(TreeNode root) { List<List<Integer>> res = new ArrayList<>(); getLevel(root, res, 0); return res; } private void getLevel(TreeNode root, List<List<Integer>> res, int level){ if(root == null) return; List<Integer> list = null; if(res.size() == level) { list = new ArrayList<>(); res.add(list); } else { list = res.get(level); } list.add(root.val); getLevel(root.left, res, level+1); getLevel(root.right, res, level+1); } }
把二叉树的每一层的结点从下到上打印出来。
如给定二叉树:
返回:
public class Solution { public List<List<Integer>> levelOrderBottom(TreeNode root) { List<List<Integer>> res = new ArrayList<>(); create(root, res, 0); return res; } private void create(TreeNode root, List<List<Integer>> res, int level){ if(root == null) return; List<Integer> list = null; if(res.size() == level){ //该层不在链表中 list = new LinkedList<>(); res.add(0, list); } else { list = res.get(res.size() - level - 1); } list.add(root.val); //前序遍历 create(root.left, res, level + 1); create(root.right, res, level + 1); } }
判断一颗二叉树是否是镜像二叉树
public class Solution {
public boolean isSymmetric(TreeNode root) {
if(root == null) return true;
return helper(root.left, root.right);
}
private boolean helper(TreeNode left, TreeNode right){
if(left == null || right == null) return left == right; // == 比较的是是否是同一个对象,这里只有left和right都是null的时候才会返回true
if(left.val != right.val) return false;
return helper(left.left, right.right) && helper(left.right, right.left);
}
}
反转二叉树
如给定二叉树:
返回:
public class Solution {
public TreeNode invertTree(TreeNode root) {
if(root == null) return root;
TreeNode left = root.left;
TreeNode right = root.right;
root.left = invertTree(right);
root.right = invertTree(left);
return root;
}
}
在一颗二叉查找树里面找两个结点的第一个公共祖先。
思路:这是一颗二叉查找树,可以利用它的性质:root.left.val <= root.val < root.right.val ,有下面三种情况:
public class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
while((root.val - p.val) * (root.val - q.val) > 0){
root = p.val < root.val? root.left: root.right;
}
return root;
}
}
判断两颗二叉树是否相等。
public class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p == null || q == null) return p == q;
if(p.val != q.val) return false;
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
}
返回一颗二叉树的最小深度。
public class Solution {
public int minDepth(TreeNode root) {
if(root == null) return 0;
int left = minDepth(root.left);
int right = minDepth(root.right);
return (left == 0 || right == 0) ? left + right + 1: Math.min(left, right) + 1;
}
}
返回一颗二叉树的最大深度。
public class Solution {
public int maxDepth(TreeNode root) {
if(root == null) return 0;
return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}
}
给定一颗二叉树和一个值sum,判断这个值sum是否是由二叉树的某一个根节点到叶子节点的路径上结点的值的和(路径和)。
public class Solution {
public boolean hasPathSum(TreeNode root, int sum) {
if(root != null && root.left == null && root.right == null && sum == root.val) return true;
else if(root == null) return false;
else {
return hasPathSum(root.left, sum-root.val) || hasPathSum(root.right, sum-root.val);
}
}
}
返回一颗二叉查找树的第k小的元素
public class Solution { int count = 0; int val; public int kthSmallest(TreeNode root, int k) { traverse(root, k); return val; } private void traverse(TreeNode root, int k){ if(root == null) return; traverse(root.left, k); count++; if(k == count) val = root.val; traverse(root.right, k); } }
计算完全二叉树的结点的个数
思路:利用完全二叉树的性质,深度为n的完全二叉树的,去掉第n层变为满二叉树。则完全二叉树的结点个数为n-1的满二叉树加上最下面一层的个数
public class Solution { public int countNodes(TreeNode root) { if(root == null) return 0; else if(root.left == null) return 1; int height = 0; int sum = 0; TreeNode cur = root; while(cur.left != null){ sum += (1<<height); //1左移height位 height++; cur = cur.left; } return sum + countLastLevel(root, height); } private int countLastLevel(TreeNode root, int height){ if(height == 1) if(root.right != null) return 2; else if(root.left != null) return 1; else return 0; TreeNode lastNode = root.left; int currHeight = 1; while(currHeight<height) { currHeight++; lastNode = lastNode.right; } if(lastNode == null) return countLastLevel(root.left, height - 1); else return (1 << (height - 1)) + countLastLevel(root.right, height - 1); } }
从上到下打印二叉树每层的右边结点
public class Solution { public List<Integer> rightSideView(TreeNode root) { List<Integer> list = new LinkedList<>(); helper(list, root, 0); return list; } private void helper(List<Integer> res, TreeNode root, int level){ if(root == null) return; if(res.size() == level){ res.add(root.val); } helper(res, root.right, level + 1); helper(res, root.left, level + 1); } }
二叉树的前序遍历
要求:不能用递归
public class Solution { public List<Integer> preorderTraversal(TreeNode root) { List<Integer> res = new LinkedList<>(); if(root != null) { Stack<TreeNode> stack = new Stack<>(); stack.add(root); while(!stack.isEmpty()){ root = stack.pop(); res.add(root.val); if(root.right != null) stack.push(root.right); if(root.left != null) stack.push(root.left); } } return res; } }
每个结点的值都只可能是0~9
从根节点到叶子节点组成一个数,如1->2->3组成123
计算每个从根节点到叶子节点的数的和
如:
返回:
12 + 13 = 25
public class Solution {
public int sumNumbers(TreeNode root) {
return DFS(root, 0);
}
private int DFS(TreeNode root, int sum){
if(root == null) return 0;
if(root.left == null && root.right == null) {
return sum * 10 + root.val;
}
return DFS(root.left, sum * 10 + root.val) + DFS(root.right, sum * 10 + root.val);
}
}
public class Solution { public int rob(TreeNode root) { Map<TreeNode, Integer> dp = new HashMap<>(); return robHelper(root, dp); } private int robHelper(TreeNode root, Map<TreeNode, Integer> dp){ if(root == null) return 0; if(dp.containsKey(root)) return dp.get(root); int val = 0; if(root.left != null) val += robHelper(root.left.left, dp) + robHelper(root.left.right, dp); if(root.right != null) val += robHelper(root.right.left, dp) + robHelper(root.right.right, dp); int robRoot = root.val + val; int notRobRoot = robHelper(root.left, dp) + robHelper(root.right, dp); val = Math.max(robRoot, notRobRoot); dp.put(root, val); return val; } }
转化二叉树为右链表
如:
转为:
public class Solution {
TreeNode pre = null;
public void flatten(TreeNode root) {
if(root == null) return;
flatten(root.right);
flatten(root.left);
root.right = pre;
root.left = null;
pre = root;
}
}
给定一个二叉树和值sum,返回从根节点到叶子节点的路径和等于sum的所有路径。
思路:用回溯的万能公式
public class Solution { public List<List<Integer>> pathSum(TreeNode root, int sum) { List<List<Integer>> res = new LinkedList<>(); backTracking(root, res, new LinkedList<>(), sum); return res; } private void backTracking(TreeNode root, List<List<Integer>> res, List<Integer> list, int sum){ if(root == null) return; if(root.left == null && root.right == null && root.val == sum) { list.add(root.val); res.add(new LinkedList<>(list)); list.remove(list.size()-1); } list.add(root.val); backTracking(root.left, res, list, sum-root.val); backTracking(root.right, res, list, sum-root.val); list.remove(list.size()-1); } }
Z字形层序遍历二叉树
public class Solution { public List<List<Integer>> zigzagLevelOrder(TreeNode root) { List<List<Integer>> res = new LinkedList<>(); helper(root, res, 0); return res; } private void helper(TreeNode root, List<List<Integer>> res, int level){ if(root == null) return; List<Integer> list = null; if(res.size() == level) { list = new LinkedList<>(); res.add(list); } else { list = res.get(level); } if(level%2 == 1) { list.add(0, root.val); } else { list.add(root.val); } helper(root.left, res, level+1); helper(root.right, res, level+1); } }
把一个排序好的数组转化为二叉搜索树
public class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
if(nums == null || nums.length == 0) return null;
return helper(nums, 0, nums.length-1);
}
private TreeNode helper(int[] nums, int l, int r){
if(l > r) return null;
int mid = (l + r)/2;
TreeNode root = new TreeNode(nums[mid]);
root.left = helper(nums, l, mid-1);
root.right = helper(nums, mid+1, r);
return root;
}
}
不用递归中序遍历二叉树
public class Solution { public List<Integer> inorderTraversal(TreeNode root) { List<Integer> res = new LinkedList<>(); if(root == null) return res; Stack<TreeNode> s = new Stack<>(); while(!s.isEmpty() || root != null){ if(root != null){ s.push(root); root = root.left; } else { root = s.pop(); res.add(root.val); root = root.right; } } return res; } }
给定一个整数n,返回存储 1 ~ n 所有的二叉搜索树的个数3
思路:
我们可以用自底向上的方法,用数组:
num 存从 1~n 的每个数可以组成二叉搜索树的种数。
public class Solution {
public int numTrees(int n) {
//1 2 3 4 和 4 5 6 7是一样的
int[] num = new int[n + 1];
num[0] = 1;
num[1] = 1;
for(int i = 2; i <= n; i++){
for(int j = 1; j <=i; j++){
num[i] += num[j-1]*num[i-j];
}
}
return num[n];
}
}
给定一个整数n,返回所有的二叉搜索树存储1 ~ n
如 n = 3
返回:
思路:
用动态规划的方法,用自底向上的方法,用一个数组res存中间的结果,res[i] 表示当 n = i 的结果。
当 n = i+1 时,用 res[0 ~ j] 的值作为 i+1 的左右结点。
public class Solution { public List<TreeNode> generateTrees(int n) { List<TreeNode>[] res = new List[n+1]; res[0] = new ArrayList<TreeNode>(); if(n == 0) return res[0]; res[0].add(null); for(int len = 1; len <= n; len++){ res[len] = new ArrayList<>(); for (int j = 0; j < len; j++) { for(TreeNode l: res[j]){ for(TreeNode r: res[len-j-1]){ TreeNode root = new TreeNode(j+1); root.left = l; root.right = clone(r, j+1); res[len].add(root); } } } } return res[n]; } private TreeNode clone(TreeNode n, int offset) { if (n == null) { return null; } TreeNode node = new TreeNode(n.val + offset); node.left = clone(n.left, offset); node.right = clone(n.right, offset); return node; } }
在一颗二叉树里面找两个结点的第一个公共祖先。
public class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null || root == q || root == p) return root;
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
return left == null ? right : right == null ? left : root;
}
}
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': if root == None or p == root or q == root: return root l = self.lowestCommonAncestor(root.left, p, q) r = self.lowestCommonAncestor(root.right, p, q) if l == None: return r elif r == None: return l else: return root
恢复一颗二叉查找树,这个二叉查找树有两个元素交换了位置
public class Solution { public void recoverTree(TreeNode root) { if(root == null) return ; TreeNode[] res = new TreeNode[2]; Stack<TreeNode> s = new Stack<>(); TreeNode prev = new TreeNode(Integer.MIN_VALUE); while(!s.isEmpty() || root != null){ if(root != null){ s.push(root); root = root.left; } else { root = s.pop(); if(prev.val > root.val){ res[0] = res[0] == null? prev : res[0]; res[1] = root; } prev = root; root = root.right; } } int temp = res[0].val; res[0].val = res[1].val; res[1].val = temp; } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。