目录
106. 从中序与后序遍历序列构造二叉树
leetcode题目链接:https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal
leetcode AC记录:
思路:中序遍历是左中右,后序遍历是左右中,按照这个顺序后序数组的末尾为根,然后找到根在中序数组中的位置,将中序数组分为左右子树,递归循环这个过程即可。
代码如下:
public TreeNode buildTree(int[] inorder, int[] postorder) {
return buildTree(inorder, postorder, 0, inorder.length-1, 0, postorder.length - 1);
}
public TreeNode buildTree(int[] inorder, int[] postorder, int inBegin, int inEnd, int postBegin, int postEnd) {
if(inBegin > inEnd || postBegin > postEnd) {
return null;
}
TreeNode root = new TreeNode();
root.val = postorder[postEnd];
int rootIndex = getRootIndex(inorder, root.val, inBegin, inEnd);
root.left = buildTree(inorder, postorder, inBegin, rootIndex-1 , postBegin, postBegin + rootIndex - inBegin -1);
root.right = buildTree(inorder, postorder, rootIndex + 1, inEnd , postBegin + rootIndex - inBegin, postEnd - 1);
return root;
}
public int getRootIndex(int[] arr, int val, int begin, int end) {
while(begin <= end) {
if(arr[begin] == val) {
return begin;
}
begin++;
}
return -1;
}
112. 路径总和
leetcode题目链接:https://leetcode.cn/problems/path-sum
leetcode AC记录:
思路:使用回溯和递归,将当前节点的累加和传递到子树中,如果碰到叶子节点,判断和是否为目标值,如果是返回并将结果递归到上层,层层递归最终返回。
代码如下:
public boolean hasPathSum(TreeNode root, int targetSum) {
return pathSum(root, 0, targetSum);
}
public boolean pathSum(TreeNode node, int currentSum, int targetSum) {
if(node == null) {
return false;
}
currentSum += node.val;
if(node.left == null && node.right == null && currentSum == targetSum) {
return true;
}
boolean flag = false;
if(node.left != null) {
flag = pathSum(node.left, currentSum, targetSum);
if(flag == true) {
return true;
}
}
if(node.right != null) {
flag = pathSum(node.right, currentSum, targetSum);
if(flag == true) {
return true;
}
}
return flag;
}
404. 左叶子之和
leetcode题目链接:https://leetcode.cn/problems/sum-of-left-leaves/
leetcode AC记录:
思路:使用递归方式前序遍历,返回条件为遇到左右子树为空,如果判断遇到了左叶子节点,则累加左叶子节点的值。
代码如下:
public int sumOfLeftLeaves(TreeNode root) {
if(root == null) {
return 0;
}
if(root.left == null && root.right == null) {
return 0;
}
int leftSum = sumOfLeftLeaves(root.left);
if(root.left != null && root.left.left == null && root.left.right == null) {
leftSum = root.left.val;
}
int rightSum = sumOfLeftLeaves(root.right);
return leftSum + rightSum;
}
513. 找树左下角的值
leetcode题目链接:https://leetcode.cn/problems/find-bottom-left-tree-value/
leetcode AC记录:
思路:层序遍历,找到最后一层第一个元素即可。
代码如下:
public int findBottomLeftValue(TreeNode root) {
Deque<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int res = root.val;
while(!queue.isEmpty()) {
int size = queue.size();
int index = 0;
while(index < size) {
TreeNode node = queue.pollFirst();
if(index == 0) {
res = node.val;
}
index++;
if(node.left != null) {
queue.offer(node.left);
}
if(node.right != null) {
queue.offer(node.right);
}
}
}
return res;
}
530. 二叉搜索树的最小绝对差
leetcode题目链接:https://leetcode.cn/problems/minimum-absolute-difference-in-bst
leetcode AC记录:
思路:使用中序迭代法遍历二叉树,因为是二叉搜索树,所以中序遍历是有序的,只需要记录上一个节点的值,和当前节点做差和最小差值进行比较赋值即可。
代码如下:
public int getMinimumDifference(TreeNode root) {
TreeNode cur = root;
int minDiff = Integer.MAX_VALUE;
Stack<TreeNode> stack = new Stack<>();
TreeNode pre = null;
while(!stack.empty() || cur != null) {
if(cur != null) {
stack.push(cur);
cur = cur.left;
} else {
TreeNode node = stack.pop();
if(pre != null && node != null) {
minDiff = Math.min(Math.abs(pre.val - node.val), minDiff);
}
pre = node;
cur = node.right;
}
}
return minDiff;
}
235. 二叉搜索树的最近公共祖先
leetcode题目链接:https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree
leetcode AC记录:
思路:利用二叉搜索树的特性,左子树比根小,右子树比根大,如果根的值大于p并且大于q,说明公共祖先在当前节点的左子树中,如果根的值小于p并且小于q,说明公共祖先在当前节点的右子树中。
代码如下:
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
while(root != null) {
if(root.val > p.val && root.val > q.val) {
root = root.left;
} else if(root.val < p.val && root.val < q.val) {
root = root.right;
} else {
return root;
}
}
return null;
}
98. 验证二叉搜索树
leetcode题目链接:https://leetcode.cn/problems/validate-binary-search-tree
leetcode AC记录:
思路:递归判断。注意一点,只需要判断当前节点是否符合大于给定上限,小于给定下限,如果是左节点,上限为根节点的值,如果是右节点,下限为根节点的值。
代码如下:
public boolean isValidBST(TreeNode root) {
return isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE);
}
public boolean isValidBST(TreeNode root, long begin, long end) {
if(root == null) {
return true;
}
if(root.val <= begin || root.val >= end) {
return false;
}
return isValidBST(root.left, begin, (long)root.val) && isValidBST(root.right, root.val, end);
}
701. 二叉搜索树中的插入操作
leetcode题目链接:https://leetcode.cn/problems/insert-into-a-binary-search-tree/
leetcode AC记录:
思路:通过二叉搜索树的特点确定插入的位置,确定后作为叶子节点插入。
代码如下:
public TreeNode insertIntoBST(TreeNode root, int val) {
if(root == null) {
return new TreeNode(val);
}
//确定插入的位置 true代表左 false代表右
boolean flag = true;
TreeNode res = root;
TreeNode pre = root;
while(root != null) {
pre = root;
if(root.val > val) {
root = root.left;
flag = true;
} else if(root.val < val) {
root = root.right;
flag = false;
}
}
TreeNode node = new TreeNode(val);
if(flag) {
pre.left = node;
} else {
pre.right = node;
}
return res;
}
700. 二叉搜索树中的搜索
leetcode题目链接:https://leetcode.cn/problems/search-in-a-binary-search-tree/
leetcode AC记录:
思路:递归搜索。
代码如下:
public TreeNode searchBST(TreeNode root, int val) {
if(root == null) {
return null;
}
if(root.val == val) {
return root;
} else if(root.val > val) {
return searchBST(root.left, val);
} else {
return searchBST(root.right, val);
}
}
108. 将有序数组转换为二叉搜索树
leetcode题目链接:https://leetcode.cn/problems/convert-sorted-array-to-binary-search-tree
leetcode AC记录:
思路:二叉搜索树为有序的树,左子树比根小,右子树比根大,所以每次取数组中间节点当作根,然后将数组根据根节点位置分为左右子树,递归这个过程直到数组下标不符合要求(或者左右子树为空)。
代码如下:
public TreeNode sortedArrayToBST(int[] nums) {
//取中间的作为根节点
return buildTree(nums, 0, nums.length-1);
}
public TreeNode buildTree(int[] nums, int begin, int end) {
if(begin < 0 || end >= nums.length || begin > end) {
return null;
}
int mid = (end - begin) / 2 + begin;
TreeNode root = new TreeNode(nums[mid]);
root.left = buildTree(nums, begin, mid - 1);
root.right = buildTree(nums, mid + 1, end);
return root;
}
236. 二叉树的最近公共祖先
leetcode题目链接:https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/
leetcode AC记录:
思路:这道题有点难,使用前序遍历,如果当前节点包含q或者p,返回当前节点,如果左右子树都不为空返回结果(题目中的前提是肯定会包含p和q)。
代码如下:
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == q || root == p || root == null) {
return root;
}
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if(left != null && right != null) {
return root;
} else if(left == null && right != null) {
return right;
} else if(left != null && right == null) {
return left;
} else {
return null;
}
}
501. 二叉搜索树中的众数
leetcode题目链接:https://leetcode.cn/problems/find-mode-in-binary-search-tree/
leetcode AC记录:
思路:使用迭代法中序遍历,那么遍历过程是一个有序的数组,记录出现元素最多的次数maxCount,如果当前的次数大于maxCount,清空结果数组,将当前节点值放入结果数组;如果当前节点值次数等于maxCount,将当前节点放入结果数组。
代码如下:
public int[] findMode(TreeNode root) {
List<Integer> list = new ArrayList<>(16);
int maxCount = 0;
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
Integer preval = null;
int curCount = 1;
while(!stack.empty() || cur != null) {
if(cur != null) {
stack.push(cur);
cur = cur.left;
}else {
TreeNode node = stack.pop();
if(preval == null) {
curCount = 1;
}else if(node.val == preval) {
curCount++;
} else {
curCount = 1;
}
if(maxCount < curCount) {
maxCount = curCount;
list.clear();
list.add(node.val);
} else if(maxCount == curCount){
list.add(node.val);
}
preval = node.val;
cur = node.right;
}
}
return list.stream().mapToInt(Integer::valueOf).toArray();
}
538. 把二叉搜索树转换为累加树
leetcode题目链接:https://leetcode.cn/problems/convert-bst-to-greater-tree/
leetcode AC记录:
思路:使用迭代法中序遍历,区别在于先遍历右节点,即右中左,遍历节点累加赋值即可。
代码如下:
public TreeNode convertBST(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
int sum = 0;
while(!stack.empty() || cur != null) {
if(cur != null) {
stack.push(cur);
cur = cur.right;
}else {
TreeNode node = stack.pop();
sum += node.val;
node.val = sum;
cur = node.left;
}
}
return root;
}
669. 修剪二叉搜索树
leetcode题目链接:https://leetcode.cn/problems/trim-a-binary-search-tree/
leetcode AC记录:
思路:如果当前节点值在范围里,递归处理左右子树;如果当前节点值小于下限,根据二叉搜索树的特点,说明当前节点的左子树也不符合条件,返回当前节点的右子树并递归处理,当前节点大于上限同理处理。
代码如下:
public TreeNode trimBST(TreeNode root, int low, int high) {
if(root == null) {
return null;
} else if(root.val >= low && root.val <= high) {
root.left = trimBST(root.left, low, high);
root.right = trimBST(root.right, low, high);
} else if(root.val < low){
return trimBST(root.right, low, high);
} else if(root.val > high) {
return trimBST(root.left, low, high);
}
return root;
}
450. 删除二叉搜索树中的节点
leetcode题目链接:https://leetcode.cn/problems/delete-node-in-a-bst/
leetcode AC记录:
思路:删除二叉搜索树的节点相对于增加节点难很多,删除后需要调整树的结构。难点在于递归的处理细节,刚开始写的时候我会想如果删除的是根节点该如何处理,其实出发点不对,只需要考虑当前节点该如何操作就行:如果当前节点大于key,递归删除左节点;如果当前节点小于key,递归删除右节点;如果当前节点等于key,需要删除当前节点。下面讨论下如何删除当前节点:
如果当前节点的左右子树为空,说明删除的是叶子节点,直接返回空;
如果当前节点的左右子树其中一个为空,返回不为空的;
如果当前节点的左右子树都不为空,把右子树当作根,左子树应该放到右子树的最左的叶子节点处。
代码如下:
public TreeNode deleteNode(TreeNode root, int key) {
if(root == null) {
return null;
}else if(root.val > key) {
root.left = deleteNode(root.left, key);
} else if(root.val < key) {
root.right = deleteNode(root.right, key);
} else {
if(root.left == null) {
return root.right;
} else if(root.right == null) {
return root.left;
} else {
TreeNode res = root.right;
TreeNode left = root.left;
TreeNode right = root.right;
while(right.left != null) {
right = right.left;
}
right.left = left;
return res;
}
}
return root;
}
257. 二叉树的所有路径
leetcode题目链接:https://leetcode.cn/problems/binary-tree-paths
leetcode AC记录:
思路:回溯和递归,递归用来遍历二叉树,回溯用来回退节点。
代码如下:
public List<String> binaryTreePaths(TreeNode root) {
List<Integer> list = new ArrayList<>(16);
List<String> res = new ArrayList<>(16);
traversal(root, list, res);
return res;
}
public void traversal(TreeNode node, List<Integer> path, List<String> res) {
if(node == null) {
return;
}
path.add(node.val);
if(node.left == null && node.right == null) {
res.add(path.stream().map(String::valueOf).collect(Collectors.joining("->")));
return;
}
if(node.left != null) {
traversal(node.left, path, res);
path.remove(path.size()-1);
}
if(node.right != null) {
traversal(node.right, path, res);
path.remove(path.size()-1);
}
}
110. 平衡二叉树
leetcode题目链接:https://leetcode.cn/problems/balanced-binary-tree
leetcode AC记录:
思路:使用后序递归遍历二叉树,返回条件为遇到空节点高度为0。分别判断左右子树的高度,高度是从叶子节点开始累加计算,如果高度差不符合要求返回-1。
代码如下:
public boolean isBalanced(TreeNode root) {
return high(root) != -1;
}
public int high(TreeNode node) {
if(node == null) return 0;
int leftHeight = high(node.left);
int rightHeight = high(node.right);
if(leftHeight == -1 || rightHeight == -1) {
return -1;
}
int abs = Math.abs(leftHeight - rightHeight);
if(abs > 1) {
return -1;
}
return Math.max(leftHeight, rightHeight) + 1;
}
617. 合并二叉树
leetcode题目链接:https://leetcode.cn/problems/merge-two-binary-trees/
leetcode AC记录:
思路:递归合并,如果树1为空,返回树2;如果树2为空,返回树1;如果都不为空,树1的节点值累加树2的值,最后返回树1的根。
代码如下:
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if(root1 == null && root2 == null) {
return null;
} else if(root1 == null && root2 != null) {
return root2;
} else if(root1 != null && root2 == null) {
return root1;
}
if(root1 != null && root2 != null) {
root1.val += root2.val;
root1.left = mergeTrees(root1.left, root2.left);
root1.right = mergeTrees(root1.right, root2.right);
}
return root1;
}
654. 最大二叉树
leetcode题目链接:https://leetcode.cn/problems/maximum-binary-tree/
leetcode AC记录:
思路:递归,和使用数组构建二叉搜索树类似。
代码如下:
public TreeNode constructMaximumBinaryTree(int[] nums) {
return construct(nums, 0, nums.length-1);
}
public TreeNode construct(int[] nums, int beginIndex, int endIndex) {
if(beginIndex < 0 || endIndex >= nums.length || beginIndex > endIndex) {
return null;
}
int maxIndex = maxIndex(nums, beginIndex, endIndex);
TreeNode root = new TreeNode(nums[maxIndex]);
root.left = construct(nums, beginIndex, maxIndex-1);
root.right = construct(nums, maxIndex+1, endIndex);
return root;
}
public int maxIndex(int[] nums, int beginIndex, int endIndex) {
int index = beginIndex;
while(++beginIndex <= endIndex) {
if(nums[index] < nums[beginIndex]) {
index = beginIndex;
}
}
return index;
}