劍指offer(六):二叉樹上(cpp)

1.重建二叉樹

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

class Solution {
public:
    TreeNode* rebuild(vector<int> &pre, int pres,int pred,vector<int> &vin,int vins,int vind){
        TreeNode *root = new TreeNode(pre[pres]);
        if(pres==pred && vins==vind && pre[pres]==vin[vins])
            return root;
        int leftlen = find(vin.begin()+vins,vin.begin()+vind+1,pre[pres])-(vin.begin()+vins);
        if(leftlen>0){      //有左子樹在執行
            root->left = rebuild(pre,pres+1,pres+leftlen,vin,vins,vins+leftlen-1);
        }
        if(leftlen<pred-pres){//有右子樹在執行
            root->right = rebuild(pre,pres+leftlen+1,pred,vin,vins+leftlen+1,vind);
        }
        return root;
    }
    TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
        if(pre.empty()||vin.empty()||pre.size()!=vin.size())
            return nullptr;
        TreeNode *root = rebuild(pre,0,pre.size()-1,vin,0,vin.size()-1);
        return root;
    }
};

2. 樹的子結構

輸入兩棵二叉樹A,B,判斷B是不是A的子結構。(ps:我們約定空樹不是任意一個樹的子結構)

class Solution {
public:
    bool DoesHave(TreeNode* p1,TreeNode* p2){
        if(p2==nullptr)
            return true;
        if(p1==nullptr)
            return false;
        if(p1->val != p2->val)
            return false;
        return DoesHave(p1->left,p2->left)&&DoesHave(p1->right,p2->right);
    }
    bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
    {
        bool res = false;
        if(pRoot1==nullptr||pRoot2==nullptr)
            return res;
        if(pRoot1->val == pRoot2->val)
            res = DoesHave(pRoot1,pRoot2);
        if(!res)
            res = HasSubtree(pRoot1->left,pRoot2);
        if(!res)
            res = HasSubtree(pRoot1->right,pRoot2);
        return res;
    }
};

3. 二叉樹的鏡像

操作給定的二叉樹,將其變換爲源二叉樹的鏡像。

class Solution {
public:
    void Mirror(TreeNode *pRoot) {
        if(!pRoot || (pRoot->left==nullptr&&pRoot->right==nullptr))
            return;
        swap(pRoot->left,pRoot->right);
        if(pRoot->left)
            Mirror(pRoot->left);
        if(pRoot->right)
            Mirror(pRoot->right);
    }
};

4. 從上往下打印二叉樹

從上往下打印出二叉樹的每個節點,同層節點從左至右打印。

class Solution {
public:
    vector<int> PrintFromTopToBottom(TreeNode* root) {
        vector<int>res;
        if(!root)
            return res;
        queue<TreeNode *> assit;
        assit.push(root);
        while(!assit.empty()){
            TreeNode *tmp = assit.front();
            assit.pop();
            if(tmp->left)
                assit.push(tmp->left);
            if(tmp->right)
                assit.push(tmp->right);
            res.push_back(tmp->val);
        }
        return res;
    }
};

5. 二叉搜索樹的後序遍歷序列

輸入一個整數數組,判斷該數組是不是某二叉搜索樹的後序遍歷的結果。如果是則輸出Yes,否則輸出No。假設輸入的數組的任意兩個數字都互不相同。

class Solution {
public:
    bool Istree(vector<int> &seq, int start,int end,int root){
        if(start == end)
            return true;
        auto iter = find_if(seq.begin()+start,seq.begin()+end,[root](int x){return x>root;});
        int len = iter-(seq.begin()+start);
        if(find_if(seq.begin()+start+len,seq.begin()+end,[root](int x){return x<root;})!=(seq.begin()+end))
            return false;
        bool left=true,right=true;
        if(len>0)
            left = Istree(seq,start,start+len-1,seq[start+len-1]);
        if(len<end-start)
            right = Istree(seq,start+len,end-1,seq[end-1]);
        return left&&right;
    }
    bool VerifySquenceOfBST(vector<int> sequence) {
        if(sequence.empty())
            return false;
        int len = sequence.size();
        bool res = Istree(sequence,0,len-1,sequence[len-1]);
        return res;
    }
};

6. 二叉樹的深度

輸入一棵二叉樹,求該樹的深度。從根結點到葉結點依次經過的結點(含根、葉結點)形成樹的一條路徑,最長路徑的長度爲樹的深度。

class Solution {
public:
    int TreeDepth(TreeNode* pRoot)
    {
        if(pRoot==nullptr)
            return 0;
        int lh = TreeDepth(pRoot->left);
        int rh = TreeDepth(pRoot->right);
        return 1+((lh>rh)?lh:rh);
    }
};

7.二叉樹中和爲某一值的路徑

輸入一顆二叉樹的根節點和一個整數,打印出二叉樹中結點值的和爲輸入整數的所有路徑。路徑定義爲從樹的根結點開始往下一直到葉結點所經過的結點形成一條路徑。(注意: 在返回值的list中,數組長度大的數組靠前)

class Solution {
    vector<vector<int>> res;
public:
    static bool compare(vector<int>& v1, vector<int>& v2){
        return v1.size()>v2.size();
    }
    void FindPath(TreeNode* root,int exnum,vector<int> &path,int csum){
        csum += root->val;
        path.push_back(root->val);
        if(root->left==nullptr&&root->right==nullptr&&csum==exnum)
            res.push_back(path);
        if(root->left)
            FindPath(root->left,exnum,path,csum);
        if(root->right)
            FindPath(root->right,exnum,path,csum);
        path.pop_back();
    }
    vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
        if(root==nullptr)
            return res;
        vector<int> path;
        int csum = 0;
        FindPath(root,expectNumber,path,csum);
        sort(res.begin(),res.end(),compare);
        return res;
    }
};

活脫脫是二叉樹前序遍歷的有效使用,到達葉子節點之後若路徑和與期待值相等就表示當前路徑可取,否則返回上一層,注意取了引用的參數要手動回覆上一層的值,值傳遞的不用管,如上面的csum變量。

8. 平衡二叉樹

輸入一棵二叉樹,判斷該二叉樹是否是平衡二叉樹。

  • 一、暴力遞歸,對每一個節點都進行一次比較高度求解若滿足二叉平衡樹的要求就繼續向下遞歸,直到葉子節點。缺點是對好多節點進行了多次計算,優點是易於編碼實現。
class Solution {
public:
    int TreeDepth(TreeNode* root){
        if(root==nullptr)
            return 0;
        int left = TreeDepth(root->left);
        int right = TreeDepth(root->right);
        return 1+(left>right?left:right);
    }
    bool IsBalanced_Solution(TreeNode* pRoot) {
        if(pRoot==nullptr)
            return true;
        int left = TreeDepth(pRoot->left);
        int right = TreeDepth(pRoot->right);
        if(left-right>1 || left-right<-1)
            return false;
        return IsBalanced_Solution(pRoot->left)&&IsBalanced_Solution(pRoot->right);
    }
};
  • 二、基於後序遍歷處理,添加一個變量記錄子樹的深度,遞歸返回父節點的時候利用子節點的高度直接可得到父節點的深度。
class Solution {
public:
    bool IsBalanced(TreeNode* root, int& depth){
        if(root==nullptr){
            depth = 0;
            return true;
        }
        int left,right;
        if(IsBalanced(root->left,left)&&IsBalanced(root->right,right)){
            if(left-right<=1&&left-right>=-1){
                depth = 1+(left>right?left:right);
                return true;
            }
        }
        return false;
    }
    bool IsBalanced_Solution(TreeNode* pRoot) {
        if(pRoot==nullptr)
            return true;
        int pDepth;
        return IsBalanced(pRoot,pDepth);
    }
};

9. 二叉樹的下一個結點

給定一個二叉樹和其中的一個結點,請找出中序遍歷順序的下一個結點並且返回。注意,樹中的結點不僅包含左右子結點,同時包含指向父結點的指針。

class Solution {
public:
    TreeLinkNode* GetNext(TreeLinkNode* pNode)
    {
        if(pNode==nullptr)
            return nullptr;
        TreeLinkNode* pNext;
        if(pNode->right){
            TreeLinkNode* right = pNode->right;
            while(right->left){
                right = right->left;
            }
            pNext = right;
        }else if(pNode->next){
            TreeLinkNode* current = pNode;
            TreeLinkNode* parent = pNode->next;
            while(parent!=nullptr&&current==parent->right){
                current = parent;
                parent = parent->next;
            }
            pNext = parent;
        }
        return pNext;
    }
};

考慮問題要全面,分清主次,三種情況:

  • 有右子樹,找到右子樹的最左邊的節點
  • 無右子樹,但本身是左節點直接返回父節點
  • 既無右子樹,本身還是右子樹就向上尋找直到節點的某個祖先節點爲其父的左子樹節點的時候,返回這個祖先的父節點。

10.對稱的二叉樹

請實現一個函數,用來判斷一顆二叉樹是不是對稱的。注意,如果一個二叉樹同此二叉樹的鏡像是同樣的,定義其爲對稱的。

class Solution {
public:
    bool Issame(TreeNode* root1,TreeNode* root2){
        if(root1==nullptr&&root2==nullptr)
            return true;
        if(root1==nullptr || root2==nullptr)
            return false;
        if(root1->val != root2->val)
            return false;
        return Issame(root1->left,root2->right)&&Issame(root1->right,root2->left);
    }
    bool isSymmetrical(TreeNode* pRoot)
    {
        return Issame(pRoot,pRoot);
    }

};

這個遞歸用的太秒了,雖然本質上仍然是前序遍歷,除此之外還可以用作判斷兩棵樹是否爲同一棵樹

11. 按之字形順序打印二叉樹

請實現一個函數按照之字形打印二叉樹,即第一行按照從左到右的順序打印,第二層按照從右至左的順序打印,第三行按照從左到右的順序打印,其他行以此類推。

class Solution {
public:
    vector<vector<int> > Print(TreeNode* pRoot) {
        vector<vector<int> > res;
        if(pRoot==nullptr)
            return res;
        stack<TreeNode*>list[2];
        int current = 0;
        int next = 1;
        vector<int> path;
        list[current].push(pRoot);
        while(!list[0].empty()||!list[1].empty()){
            TreeNode* tmp = list[current].top();
            path.push_back(tmp->val);
            list[current].pop();
            if(current==0){
                if(tmp->left)
                    list[next].push(tmp->left);
                if(tmp->right)
                    list[next].push(tmp->right);
            }else {
                if(tmp->right)
                    list[next].push(tmp->right);
                if(tmp->left)
                    list[next].push(tmp->left);
            }
            if(list[current].empty()){
                current = 1-current;
                next = 1-next;
                res.push_back(path);
                path.erase(path.begin(),path.end());
            }
        }
        return res;
    }
};
發佈了39 篇原創文章 · 獲贊 7 · 訪問量 4383
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章