重建二叉樹

引言

這兩天偶然看到一道題,應該是《劍指offer》上的,原題如下:


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


解題思路

在解題之前我們需要知道前序,中序,後序是怎麼遍歷的,這裏不多做介紹。我們將前序遍歷序列設爲pre,中序遍歷序列設爲vin。

1. 首先我們需要確定根節點,很簡單,就是前序遍歷的第一個元素pre[0]=1;


2. 因爲對於中序遍歷,根節點左邊的節點位於二叉樹的左邊,根節點右邊的節點位於二叉樹的右邊



這樣我們就把整個序列分爲了兩部分,{4,7,2}在根節點的左邊,{5,3,8,6}在根節點的右邊

3. 針對{4,7,2},{5,3,8,6}分別重複執行第二步,直到所有節點都分配完畢,具體步驟如下:

3.1 對於{4,7,2},查看前序遍歷序列{1,2,4,7,3,5,6,8},發現1後面的節點爲2,也就是說2爲{4,7,2}這個左分支的根節點;


注意上圖中此時沒有右樹

3.2 依次類推,直接上圖;


3.3 對於{5,3,8,6}重建的方法和左樹一樣,直接上圖;


3.4 每一步其實就是利用前序遍歷序列找到根節點,再利用中序遍歷序列將左右子樹分開,最後再合併起來;



代碼

將解題思路總結爲代碼,如下:

TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) 
{
    int inlen=vin.size();
  
    if(pre.empty() || vin.empty()) return NULL;
    else if(inlen != pre.size()) return NULL;
  
    vector<int> left_pre,right_pre,left_in,right_in;
  
    //創建根節點,根節點爲前序遍歷的第一個元素 
    TreeNode* head=new TreeNode(pre[0]);
  
    //找到中序遍歷根節點所在位置,存放於變量gen中
    int gen=0;
    for(int i=0;i<inlen;i++)
    {
  	if (vin[i]==pre[0])
	{
  		gen=i;
		break;
	}
    }
  
    //對於中序遍歷,根節點左邊的節點位於二叉樹的左邊,根節點右邊的節點位於二叉樹的右邊
    for(int i=0;i<gen;i++)	//找到左樹 
    {
	left_in.push_back(vin[i]);
	left_pre.push_back(pre[i+1]);
    }
  
    for(int i=gen+1;i<inlen;i++)	//找到右樹 
    {
	right_in.push_back(vin[i]);
	right_pre.push_back(pre[i]);
    }

    //遞歸,劃分子樹的左、右樹,直到葉節點
    head->left=reConstructBinaryTree(left_pre,left_in);

    head->right=reConstructBinaryTree(right_pre,right_in);
  
    return head;
}


代碼比較簡單,但是還是讓我們來看看大神的code(java):
public class Solution {
    public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
        TreeNode root=reConstructBinaryTree(pre,0,pre.length-1,in,0,in.length-1);
        return root;
    }
    //前序遍歷{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6}
    private TreeNode reConstructBinaryTree(int [] pre,int startPre,int endPre,int [] in,int startIn,int endIn) {
         
        if(startPre>endPre||startIn>endIn)
            return null;
        TreeNode root=new TreeNode(pre[startPre]);
         
        for(int i=startIn;i<=endIn;i++)
            if(in[i]==pre[startPre]){
                root.left=reConstructBinaryTree(pre,startPre+1,startPre+i-startIn,in,startIn,i-1);
                root.right=reConstructBinaryTree(pre,i-startIn+startPre+1,endPre,in,i+1,endIn);
            }
                 
        return root;
    }
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章