劍指offer(四)——重建二叉樹

劍指offer(四)——重建二叉樹

題目描述
輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。

題解:
已知前序遍歷和中序遍歷求二叉樹。
我們需要找到前序遍歷數組pre[]和中序遍歷數組in[]確定二叉樹的規律。
1
2
根據前序遍歷的性質,我們可以從pre[0]知道節點1是該樹的根節點,然後在in[]中找到節點1,根據中序遍歷的性質,我們可以知道in[0] ~ in[2]是該樹的左子樹,in[4] ~ in[7]是該樹的右子樹。接下從pre[1]可以知道節點2是子樹in[0] ~ in[2]的根節點,從in[]中找到節點2,我們可以知道in[0] ~ in[1]是子樹in[0] ~ in[2]的左子樹,而且它沒有右子樹,可以發現,這個做法可以不斷循環下去,這就是它的規律了。
因此用遞歸的方式來表示這個過程如下:

  • 通過pre數組確定根節點
  • 在in數組中找到根節點的位置,確定左右子樹的範圍大小
  • 不斷重複這個過程直至找到所有節點
    代碼如下
	public static class TreeNode {
		int val;
		TreeNode left;
		TreeNode right;
		TreeNode(int x) { val = x; }
	}
	public static TreeNode reConstructBinaryTree(int [] pre,int [] in) {
		if (pre == null || in == null) {
			return null;
		}
//		利用HashMap來查找根節點在中序遍歷中的下標,以此確定下一顆子樹的範圍
		HashMap<Integer, Integer> map = new HashMap<>();
		for(int i = 0; i < in.length; i++) {
			map.put(in[i], i);
		}
        return Search(pre, 0, pre.length - 1, in, 0, in.length - 1, map);
    }
//	(l_pre,r_pre)表示該子樹在前序遍歷中的下標範圍,(l_in,r_in)表示該子樹在中序遍歷中的下標範圍
	public static TreeNode Search(int[] pre, int l_pre, int r_pre, int[] in, int l_in, int r_in, HashMap<Integer, Integer> map) {
//      當沒有該子樹時,返回null
		if (l_pre > r_pre) {
			return null;
		}
		int index = map.get(pre[l_pre]);
		TreeNode head = new TreeNode(pre[l_pre]);
		head.left = Search(pre, l_pre + 1, l_pre + index - l_in, in, l_in, index - 1, map);
		head.right = Search(pre, l_pre + index - l_in + 1, r_pre, in, index + 1, r_in, map);
		return head;
	}
	//輸出後序遍歷
	public static void Print(TreeNode tree) {
		if (tree == null) {
			return;
		}
		Print(tree.left);
		Print(tree.right);
		System.out.println(tree.val);
	}
	
	public static void main(String[] args) {
		int[] pre = new int[] {1,2,4,7,3,5,6,8};
		int[] in = new int[] {4,7,2,1,5,3,8,6};
		TreeNode resultTree = reConstructBinaryTree(pre, in);
		Print(resultTree);
	}

搜索函數主要難點在於下一顆左右子樹範圍的確認,以下說明助你理解。

  • 因爲已知下一顆子樹根節點,所以在in數組中可以快速地判斷下一顆左右子樹的範圍
  • 在知道了左右子樹的範圍之後,就可以在pre數組中快速的表示出下一顆左右子樹的範圍了
  • 可知pre數組中下一顆左子樹的範圍爲本子樹左邊界加一到本子樹左邊界加上左子樹範圍大小,即表示爲(l_pre + 1,l_pre + ((index - 1) - l_in) + 1)–>(l_pre + 1,l_pre + index - l_in)
  • 可知pre數組中下一顆右子樹的範圍爲本子樹下一顆左子樹的右邊界加一到本子樹的右邊界,即表示爲(l_pre + index - l_in + 1,r_pre)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章