236. 二叉树的最近公共祖先

思路:关键点:
- 左右子树各有其中一个已知节点;如果一个节点的左子树没有两个节点的任意一个,那么祖先肯定在其右子树上。
如果在遍历过程中,当前遍历的节点是其中一个移植节点,那当前结点就是公共祖先的候选人。
class Solution {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {if (root == p || root == q) return root;//找到公共祖先候选人if (root == null) return null;TreeNode left = lowestCommonAncestor(root.left, p, q);TreeNode right = lowestCommonAncestor(root.right, p, q);if (left != null && right != null) return root;return left != null ? left : right;}}
235. 二叉搜索树的最近公共祖先

class Solution {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {if (root == null) return root;if (root.val > p.val && root.val > q.val) {return lowestCommonAncestor(root.left, p, q);} else if (root.val < p.val && root.val < q.val) {return lowestCommonAncestor(root.right, p, q);}return root;}}
99. 恢复二叉搜索树

2,3,4,5,6,7,8
2,3, 7,5, 6,4, 8
思路:二叉搜索树在中序遍历后是有序的,如果两个节点交换后,那么就会出现两个逆序对,如果是两个相邻的节点互换,那么只会出现一个逆序对,中序遍历时,如果出现逆序对,第一个逆序对的前一个是目标元素之一,第二个逆序对的后一个元素是另一个目标元素,找到两个元素后交换一下就ok了。class Solution {TreeNode first = null;TreeNode second = null;TreeNode prev;public void recoverTree(TreeNode root) {dfs(root);int tmp = first.val;first.val = second.val;second.val = tmp;}private void dfs(TreeNode node) {if (node == null) return;dfs(node.left);if (prev != null && node.val < prev.val) {if (first == null) {first = prev;}second = node;}prev = node;dfs(node.right);}}
way2:使用Morris中序遍历,可以将空间复杂度降到O(1)
class Solution {TreeNode prev;TreeNode first;TreeNode second;public void recoverTree(TreeNode root) {if (root == null) return;while (root != null) {if (root.left != null) {TreeNode preNode = root.left;while (preNode.right != null && preNode.right != root) {preNode = preNode.right;}if (preNode.right == null) {preNode.right = root;root = root.left;} else {find(root);preNode.right = null;root = root.right;}} else {find(root);root = root.right;}}int tmp = first.val;first.val = second.val;second.val = tmp;}private void find(TreeNode node) {if (prev != null && node.val < prev.val) {if (first == null) {first = prev;}second = node;}prev = node;}}
98. 验证二叉搜索树

方法一:一开始的思路,找到前驱节点和后继节点,分别判断大小,方法不好class Solution {public boolean isValidBST(TreeNode root) {if (root == null) return true;TreeNode prev = findPredecessor(root);TreeNode successor = findSuccessor(root);if (prev != null && prev.val >= root.val) return false;if (successor != null && root.val >= successor.val) return false;return isValidBST(root.left) && isValidBST(root.right);}private TreeNode findPredecessor(TreeNode node) {TreeNode predecessor = node.left;while (predecessor != null && predecessor.right != null) {predecessor = predecessor.right;}return predecessor;}private TreeNode findSuccessor(TreeNode node) {TreeNode successor = node.right;while (successor != null && successor.left != null) {successor = successor.left;}return successor;}}
方法2:递归法,设定这棵树的最大值和最小值。要考虑节点的值是Integer的最大值和最小值。
class Solution {public boolean isValidBST(TreeNode root) {return isValid(root, Long.MAX_VALUE, Long.MIN_VALUE);}private boolean isValid(TreeNode root, long maxValue, long minValue) {if (root == null) return true;if (root.val >= maxValue) return false;if (root.val <= minValue) return false;return isValid(root.left, root.val, minValue) && isValid(root.right, maxValue, root.val);}}
方法3:dfs
class Solution {private TreeNode prev = null;private boolean res = true;public boolean isValidBST(TreeNode root) {dfs(root);return res;}private void dfs(TreeNode node) {if (node == null) return;if (res == false) return;dfs(node.left);if (prev != null && prev.val >= node.val) {res = false;}prev = node;dfs(node.right);}}
方法3:使用栈遍历
class Solution {public boolean isValidBST(TreeNode root) {if (root == null) return true;Stack<TreeNode> stack = new Stack();TreeNode prev = null;while (root != null || !stack.isEmpty()) {while (root != null) {stack.push(root);root = root.left;}TreeNode pop = stack.pop();if (prev != null && prev.val >= pop.val) {return false;}prev = pop;if (pop.right != null) {root = pop.right;}}return true;}}
333. 最大 BST 子树

思路:定义一个方法getInfo(TreeNode node),返回以node为根节点的二叉树里最大BST的信息。class Solution {public int largestBSTSubtree(TreeNode root) {if (root == null) return 0;return getInfo(root).size;}private Info getInfo(TreeNode node) {if (node == null) return null;Info li = getInfo(node.left);Info ri = getInfo(node.right);boolean lValid = (li == null) || (li.root == node.left && li.max < node.val);boolean rValid = (ri == null) || (ri.root == node.right && ri.min > node.val);if (lValid && rValid) {Info info = new Info();info.root = node;info.max = ri == null ? node.val : ri.max;info.min = li == null ? node.val : li.min;info.size = (li == null ? 0 : li.size) + (ri == null ? 0 : ri.size) + 1;return info;}if (li != null && ri != null) {return li.size > ri.size ? li : ri;}return li != null ? li : ri;}class Info {TreeNode root;Integer max;Integer min;Integer size;}}
102. 二叉树的层序遍历

class Solution {public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> res = new LinkedList();if (root == null) return res;LinkedList<TreeNode> queue = new LinkedList();queue.add(root);while (!queue.isEmpty()) {int size = queue.size();List<Integer> level = new LinkedList();while (size-- != 0) {TreeNode node = queue.pollFirst();level.add(node.val);if (node.left != null) queue.add(node.left);if (node.right != null) queue.add(node.right);}res.add(level);}return res;}}
105. 从前序与中序遍历序列构造二叉树

class Solution {public TreeNode buildTree(int[] preorder, int[] inorder) {return buildTree(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1);}private TreeNode buildTree(int[] preorder, int i1, int j1, int[] inorder, int i2, int j2) {if (i1 > j1) return null;TreeNode root = new TreeNode(preorder[i1]);int i = i2;for (; i <= j2; i++) {if (inorder[i] == preorder[i1]) break;}root.left = buildTree(preorder, i1 + 1, i1 + i - i2, inorder, i2, i - 1);root.right = buildTree(preorder, i1 + i - i2 + 1, j1, inorder, i + 1, j2);return root;}}
优化下:上面的代码每次在中序数组里寻找元素时都需要遍历,可以提前将数组对应的下标存放在一个map里
class Solution {Map<Integer,Integer> map = new HashMap();public TreeNode buildTree(int[] preorder, int[] inorder) {for (int i = 0; i < inorder.length; i++) {map.put(inorder[i], i);}return buildTree(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1);}private TreeNode buildTree(int[] preorder, int i1, int j1, int[] inorder, int i2, int j2) {if (i1 > j1) return null;TreeNode root = new TreeNode(preorder[i1]);int i = map.get(preorder[i1]);root.left = buildTree(preorder, i1 + 1, i1 + i - i2, inorder, i2, i - 1);root.right = buildTree(preorder, i1 + i - i2 + 1, j1, inorder, i + 1, j2);return root;}}
617. 合并二叉树

class Solution {public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {if (root1 == null) return root2;if (root2 == null) return root1;TreeNode newNode = new TreeNode(root1.val + root2.val);newNode.left = mergeTrees(root1.left, root2.left);newNode.right = mergeTrees(root1.right, root2.right);return newNode;}}
101. 对称二叉树

方法1:递归法class Solution {public boolean isSymmetric(TreeNode root) {return isSymmetric(root, root);}private boolean isSymmetric(TreeNode node1, TreeNode node2) {if (node1 == null && node2 == null) return true;if (node1 == null || node2 == null) return false;return node1.val == node2.val && isSymmetric(node1.left, node2.right) && isSymmetric(node1.right, node2.left);}}
