前言

关于树的算法基本解法就三类:递归,队列,栈

刷题网站推荐:

​牛客网​

​Leetcode​

1.重建二叉树

public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
if (pre.length == 0 || in.length == 0) {
return null;
}
TreeNode root = new TreeNode(pre[0]);
// 在中序中找到前序的根
for (int i = 0; i < in.length; i++) {
if (in[i] == pre[0]) {
// 左子树,注意 copyOfRange 函数,左闭右开
root.left = reConstructBinaryTree(Arrays.copyOfRange(pre, 1, i + 1), Arrays.copyOfRange(in, 0, i));
// 右子树,注意 copyOfRange 函数,左闭右开
root.right = reConstructBinaryTree(Arrays.copyOfRange(pre, i + 1, pre.length), Arrays.copyOfRange(in, i + 1, in.length));
break;
}
}
return root;
}

https://www.nowcoder.com/practice/8a19cbe657394eeaac2f6ea9b0f6fcf6?tpId=13&tqId=23282&ru=%2Fpractice%2F8a19cbe657394eeaac2f6ea9b0f6fcf6&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&sourceUrl=​​​​

2.二叉树的下一个节点

题目描述

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回 。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

public class TreeLinkNode {

int val;
TreeLinkNode left = null;
TreeLinkNode right = null;
TreeLinkNode next = null; // 指向父结点的指针

TreeLinkNode(int val) {
this.val = val;
}
}

解题思路

我们先来回顾一下中序遍历的过程:先遍历树的左子树,再遍历根节点,最后再遍历右子树。所以最左节点是中序遍历的第一个节点。

① 如果一个节点的右子树不为空,那么该节点的下一个节点是右子树的最左节点;

② 否则,向上找第一个左链接指向的树包含该节点的祖先节点。

public TreeLinkNode GetNext(TreeLinkNode pNode) {
if (pNode.right != null) {
TreeLinkNode node = pNode.right;
while (node.left != null)
node = node.left;
return node;
} else {
while (pNode.next != null) {
TreeLinkNode parent = pNode.next;
if (parent.left == pNode)
return parent;
pNode = pNode.next;
}
}
return null;
}

​https://www.nowcoder.com/practice/9023a0c988684a53960365b889ceaf5e?tpId=13&tqId=23451&ru=%2Fpractice%2F9023a0c988684a53960365b889ceaf5e&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&sourceUrl=​​​​​

3.二叉搜索树的后序遍历序列

public boolean VerifySquenceOfBST(int [] sequence) {
// 处理序列为空情况
if(sequence.length == 0) return false;
Stack<Integer> s = new Stack<>();
int root = Integer.MAX_VALUE;
// 以根,右子树,左子树顺序遍历
for(int i = sequence.length - 1; i >= 0; i--) {
// 确定根后一定是在右子树节点都遍历完了,因此当前sequence未遍历的节点中只含左子树,左子树的节点如果>root则说明违背二叉搜索的性质
if(sequence[i] > root) return false;
// 进入左子树的契机就是sequence[i]的值小于前一项的时候,这时可以确定root
while(!s.isEmpty() && s.peek() > sequence[i]) {
root = s.pop();
}
// 每个数字都要进一次栈
s.add(sequence[i]);
}
return true;
}

​https://www.nowcoder.com/practice/a861533d45854474ac791d90e447bafd?tpId=13&tqId=23289&ru=%2Fpractice%2Fa861533d45854474ac791d90e447bafd&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&sourceUrl=​​​​​

4.二叉树中和为某一值的路径

        private ArrayList<ArrayList<Integer>> res = new ArrayList<>();
private ArrayList<Integer> path = new ArrayList<>();

public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int expectNumber) {
dfs(root, expectNumber);
return res;
}

public void dfs(TreeNode root,int expectNumber) {
if(root == null) {
return;
}
path.add(root.val);
expectNumber-=root.val;
if(root.left == null && root.right == null && expectNumber == 0) {
res.add(new ArrayList<>(path));
}
dfs(root.left, expectNumber);
dfs(root.right, expectNumber);
path.remove(path.size() - 1);
}

​https://www.nowcoder.com/practice/b736e784e3e34731af99065031301bca?tpId=13&tqId=23276&ru=%2Fpractice%2Fb736e784e3e34731af99065031301bca&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&sourceUrl=​​​​​

5.二叉搜索树与双向链表

        private TreeNode pre = null;
private TreeNode head = null;

public TreeNode Convert(TreeNode pRootOfTree) {
inOrder(pRootOfTree);
return head;
}

private void inOrder(TreeNode node) {
if (node == null)
return;
inOrder(node.left);
node.left = pre;
if (pre != null)
pre.right = node;
pre = node;
if (head == null)
head = node;
inOrder(node.right);
}

​https://www.nowcoder.com/practice/947f6eb80d944a84850b0538bf0ec3a5?tpId=13&tqId=23253&ru=%2Fpractice%2F947f6eb80d944a84850b0538bf0ec3a5&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&sourceUrl=​​​​​

6.序列化二叉树

        private String deserializeStr;

String Serialize(TreeNode root) {
if (root == null)
return "#";
return root.val + " " + Serialize(root.left) + " " + Serialize(root.right);
}
TreeNode Deserialize(String str) {
deserializeStr = str;
return Deserialize();
}

private TreeNode Deserialize() {
if (deserializeStr.length() == 0)
return null;
int index = deserializeStr.indexOf(" ");
String node = index == -1 ? deserializeStr : deserializeStr.substring(0, index);
deserializeStr = index == -1 ? "" : deserializeStr.substring(index + 1);
if (node.equals("#"))
return null;
int val = Integer.valueOf(node);
TreeNode t = new TreeNode(val);
t.left = Deserialize();
t.right = Deserialize();
return t;
}

​https://www.nowcoder.com/practice/cf7e25aa97c04cc1a68c8f040e71fb84?tpId=13&tqId=23455&ru=%2Fpractice%2Fcf7e25aa97c04cc1a68c8f040e71fb84&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&sourceUrl=​​​​​

7.二叉搜索树的最近公共祖先

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);
if (root.val < p.val && root.val < q.val)
return lowestCommonAncestor(root.right, p, q);
return root;
}

https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/description/

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

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);
return left == null ? right : right == null ? left : root;
}

https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/description/