劍指Offer(第二版)面試題7:重建二叉樹
劍指Offer面試題7:重建二叉樹
題目:輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建該二叉樹。
假設輸入的前序遍歷和中序遍歷中都不包含重複的數字。例如前序遍歷序列為{1,2,4,5,3,7,6}和中序遍歷序列{4,2,5,1,7,3,6},則可以重建一棵二叉樹。如圖所示:
1
/ \
2 3
/ \ / \
4 5 7 6
思路:通過前序遍歷序列可以得到根節點,中序遍歷序列可以得到左右分別有哪些節點;通過,在左右子樹中使用此方法進行遞迴,最後,可以重建二叉樹。
已知二叉樹的前序遍歷和中序遍歷:
PreOrder: GDAFEMHZ
InOrder: ADEFGHMZ
我們基於一個事實:中序遍歷一定是 { 左子樹中的節點集合 },root,{ 右子樹中的節點集合 },前序遍歷的作用就是找到每棵子樹的root位置。
演算法
輸入:前序遍歷,中序遍歷
1、尋找樹的root,前序遍歷的第一節點G就是root。
2、觀察前序遍歷GDAFEMHZ,知道了G是root,剩下的節點必然在root的左或右子樹中的節點。
3、觀察中序遍歷ADEFGHMZ。其中root節點G左側的ADEF必然是root的左子樹中的節點,G右側的HMZ必然是root的右子樹中的節點,root不在中序遍歷的末尾或開始就說明根節點的兩顆子樹都不為空。
4、觀察左子樹ADEF,按照前序遍歷的順序來排序為DAFE,因此左子樹的根節點為D,並且A是左子樹的左子樹中的節點,EF是左子樹的右子樹中的節點。
5、同樣的道理,觀察右子樹節點HMZ,前序為MHZ,因此右子樹的根節點為M,左子節點H,右子節點Z。
import java.util.ArrayList; import java.util.LinkedList; import java.util.List; /* * 劍指Offer面試題7:重建二叉樹 * 題目:輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建該二叉樹。 * 假設輸入的前序遍歷和中序遍歷中都不包含重複的數字。例如前序遍歷序列為{1,2,4,5,3,7,6} * 和中序遍歷序列{4,2,5,1,7,3,6},則可以重建一棵二叉樹。如圖所示: * 1 / \ 2 3 / \ / \ 4 5 7 6 */ public class Test { public static void main(String[] args) { TreeNode root = new TreeNode(1); TreeNode r2 = new TreeNode(2); TreeNode r3 = new TreeNode(3); TreeNode r4 = new TreeNode(4); TreeNode r5 = new TreeNode(5); TreeNode r6 = new TreeNode(6); TreeNode r7 = new TreeNode(7); root.left = r2; root.right = r3; r2.left = r4; r2.right = r5; r3.right = r6; r3.left = r7; List<Integer> preList = new ArrayList<>(); preList.add(1); preList.add(2); preList.add(4); preList.add(5); preList.add(3); preList.add(7); preList.add(6); List<Integer> inList = new ArrayList<>(); inList.add(4); inList.add(2); inList.add(5); inList.add(1); inList.add(7); inList.add(3); inList.add(6); TreeNode reBuildTree = reBuildTree(preList, inList); levelTraversal(reBuildTree); } /** * 思路:使用遞迴的思路解決問題,分別在左右子樹中進行操作 * @param preOrderList * @param inOrderList * @return */ private static TreeNode reBuildTree(List<Integer> preOrderList,List<Integer> inOrderList){ if(preOrderList==null||inOrderList==null) return null; TreeNode root = null; // 要返回的根結點 List<Integer> leftPreOrderList; List<Integer> rightPreOrderList; List<Integer> leftInOrderList; List<Integer> rightInOrderList; int inOrderPos; int preOrderPos; if(preOrderList.size()!=0&&inOrderList.size()!=0){ // 把preorder的第一個元素作為root root = new TreeNode(preOrderList.get(0)); // 因為知道root節點了,所以根據root節點位置,把preorder,inorder分別 //劃分為 root左側 和 右側 的兩個子區間 inOrderPos = inOrderList.indexOf(preOrderList.get(0)); // inorder序列的分割點 leftInOrderList = inOrderList.subList(0, inOrderPos); rightInOrderList = inOrderList.subList(inOrderPos+1, inOrderList.size()); preOrderPos = leftInOrderList.size(); // preorder序列的分割點 leftPreOrderList = preOrderList.subList(1, preOrderPos+1); rightPreOrderList = preOrderList.subList(preOrderPos+1, preOrderList.size()); // root的左子樹就是preorder和inorder的左側區間而形成的樹 root.left = reBuildTree(leftPreOrderList, leftInOrderList); // root的右子樹就是preorder和inorder的右側區間而形成的樹 root.right = reBuildTree(rightPreOrderList, rightInOrderList); } return root; } /** * 分層遍歷二叉樹,使用一個佇列,也就是寬度優先遍歷 * @param root */ public static void levelTraversal(TreeNode root){ if(root==null) return ; LinkedList<TreeNode> queue = new LinkedList<TreeNode>(); queue.add(root); while(!queue.isEmpty()){ TreeNode cur = queue.remove(); System.out.print(cur.val+" "); if(cur.left!=null) queue.add(cur.left); if(cur.right!=null) queue.add(cur.right); } } } //建立二叉樹節點類 class TreeNode{ int val; TreeNode left; TreeNode right; public TreeNode(int val){ this.val = val; } }
引數為陣列時:
public TreeNode reConstructBinaryTree(int[] pre,int[] in) {
if(pre==null||in==null)
return null;
TreeNode root = null;
int[] preLeft = null;
int[] preRight = null;
int[] inLeft = null;
int[] inRight = null;
if(pre.length!=0&&in.length!=0){
// 得到root節點
root = new TreeNode(pre[0]);
for (int i = 0; i < in.length; i++) {
if(pre[0]==in[i]){
inLeft = Arrays.copyOfRange(in, 0, i);
inRight = Arrays.copyOfRange(in, i+1, in.length);
preLeft = Arrays.copyOfRange(pre, 1, i+1);
preRight = Arrays.copyOfRange(pre, i+1, pre.length);
}
}
root.left = reConstructBinaryTree(preLeft, inLeft);
root.right = reConstructBinaryTree(preRight, inRight);
}
return root;
}
此時需要用到Arrays.copyRange(int[ ] original , int from, int end)
如果對你有幫助,記得點贊哦~歡迎大家關注我的部落格,可以進群366533258一起交流學習哦~