4、重建二叉树
//利用原理,先序遍历的第一个节点就是根。在中序遍历中通过根 区分哪些是左子树的,哪些是右子树的
//左右子树,递归
HashMap<Integer, Integer> map = new HashMap<>();//标记中序遍历
int[] preorder;//保留的先序遍历
public TreeNode buildTree(int[] preorder, int[] inorder) {
this.preorder = preorder;
for (int i = 0; i < preorder.length; i++) {
map.put(inorder[i], i);
}
return recursive(0,0,inorder.length-1);
}
/**
* @param pre_root_idx 先序遍历的索引
* @param in_left_idx 中序遍历的索引
* @param in_right_idx 中序遍历的索引
*/
public TreeNode recursive(int pre_root_idx, int in_left_idx, int in_right_idx) {
//相等就是自己
if (in_left_idx > in_right_idx) {
return null;
}
//root_idx是在先序里面的
TreeNode root = new TreeNode(preorder[pre_root_idx]);
// 有了先序的,再根据先序的,在中序中获 当前根的索引
int idx = map.get(preorder[pre_root_idx]);
//左子树的根节点就是 左子树的(前序遍历)第一个,就是+1,左边边界就是left,右边边界是中间区分的idx-1
root.left = recursive(pre_root_idx + 1, in_left_idx, idx - 1);
//由根节点在中序遍历的idx 区分成2段,idx 就是根
//右子树的根,就是右子树(前序遍历)的第一个,就是当前根节点 加上左子树的数量
// pre_root_idx 当前的根 左子树的长度 = 左子树的左边-右边 (idx-1 - in_left_idx +1) 。最后+1就是右子树的根了
root.right = recursive(pre_root_idx + (idx-1 - in_left_idx +1) + 1, idx + 1, in_right_idx);
return root;
}
copyOfRange(original,int from,int to)该方法是从original数组的下标from开始赋值,到下标to结束,不包括下标为to的元素。实际上看完代码应该这样理解copyOfRange(original,int from,int to)该方法返回一个长度为to-from的数组,其中from~min(original.length,to)之间的元素(不包括min(original.length,to))是从数组original复制的元素,剩下的值为0
/**
* Definition for binary tree
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
import java.util.Arrays;
public class Solution {
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));
}
}
return root;
}
}
17、树的子结构
class Solution {
public boolean isSubStructure(TreeNode A, TreeNode B) {
if(A == null || B == null) return false;
return dfs(A, B) || isSubStructure(A.left, B) || isSubStructure(A.right, B);
}
public boolean dfs(TreeNode A, TreeNode B){
if(B == null) return true;
if(A == null) return false;
return A.val == B.val && dfs(A.left, B.left) && dfs(A.right, B.right);
}
}
22、从上到下打印树
BFS 通常借助 队列 的先入先出特性来实现
Queue使用时要尽量避免Collection的add()和remove()方法,而是要使用offer()来加入元素,使用poll()来获取并移出元素。它们的优点是通过返回值可以判断成功与否,add()和remove()方法在失败的时候会抛出异常。
class Solution {
public int[] levelOrder(TreeNode root) {
if (root == null) // 空树则返回空数组
return new int[0];
Queue<TreeNode> q = new LinkedList<> (); // 借助一个队列,通过 BFS 实现按层遍历二叉树
ArrayList<Integer> tmp =new ArrayList<> (); // 申请一个动态数组 ArrayList 动态添加节点值
q.offer(root); // 根结点先入队
while (q.size() != 0) {
TreeNode node = q.poll(); // 取出当前队首元素
tmp.add(node.val);
if(node.left != null) q.offer(node.left); // 左子节点入队
if(node.right != null) q.offer(node.right); // 右子节点入队
}
// 将 ArrayList 转为 int数组并返回
int[] res = new int[tmp.size()];
for (int i=0; i<res.length; i++) {
res[i] = tmp.get(i);
}
return res;
}
}
60、二叉树打印成多行
如果需要分层打印,打印多行
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<>();
List<List<Integer>> res = new ArrayList<>();
if(root != null) queue.add(root);
while(!queue.isEmpty()) {
List<Integer> tmp = new ArrayList<>();
for(int i = queue.size(); i > 0; i--) { //当前层节点数 循环
TreeNode node = queue.poll();
tmp.add(node.val);
if(node.left != null) queue.add(node.left);
if(node.right != null) queue.add(node.right);
}
res.add(tmp);
}
return res;
}
}
59、之字形顺序打印
利用双端队列的两端皆可添加元素的特性,设打印列表(双端队列) tmp ,并规定:
- 奇数层 则添加至 tmp 尾部 ,
- 偶数层 则添加至 tmp 头部
Java 中将链表 LinkedList 作为双端队列使用
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<>();
List<List<Integer>> res = new ArrayList<>();
if(root != null) queue.add(root);
while(!queue.isEmpty()) {
LinkedList<Integer> tmp = new LinkedList<>();
for(int i = queue.size(); i > 0; i--) {
TreeNode node = queue.poll();
if(res.size() % 2 == 0) tmp.addLast(node.val); // 偶数层 -> 队列头部
else tmp.addFirst(node.val); // 奇数层 -> 队列尾部
if(node.left != null) queue.add(node.left);
if(node.right != null) queue.add(node.right);
}
res.add(tmp);
}
return res;
}
}
61、序列化二叉树
public class Codec {
// Encodes a tree to a single string.
public String serialize(TreeNode root) {
if(root==null)
return "#,";
String res="";
res+=root.val+","; //前序遍历,根左右
res+=serialize(root.left);
res+=serialize(root.right);
return res;
}
//反序列化
int start=-1;
TreeNode deserialize(String str){
if(str==null || str.length()==0)
return null;//若 data 为空,直接返回 null ;
String[] strArr=str.split(",");
return deserialize(strArr);
}
TreeNode deserialize(String[] strArr){
start++;
if(start>=strArr.length || strArr[start].equals("#"))
return null;//超出索引,等于结束标志
TreeNode cur=new TreeNode(Integer.valueOf(strArr[start]));//节点出队,记为 node ;
cur.left=deserialize(strArr);//构建 node 的左子节点:node.left 的值为 vals[i] ,i在递归的时候会+1
cur.right=deserialize(strArr);//构建 node 的右子节点:node.left 的值为 vals[i] ,i在递归的时候会+1
return cur;
}
}