【刷題】劍指OFFER 二叉樹專題整理

二叉樹題目匯總

二叉樹題目匯總

我個(gè)人把涉及到二叉樹的這15到題分為4種大類,以供參考

  • 打印類

    • 從上到下打印
      - 不分行
      - 分行
    • 之字型
  • 性質(zhì)類

    • 對(duì)稱類
      • 求樹的鏡像
      • 判斷是否為對(duì)稱二叉樹
    • 平衡類
      • 判斷是否為平衡二叉樹
    • 存在類/判斷類
      • 是否包含(存在)某一子結(jié)構(gòu)
      • 是否存在和為某一值的路徑
      • 某一序列是否為二叉樹的后序遍歷
  • 參數(shù)類

    • 二叉樹的深度
    • 二叉樹的下一個(gè)結(jié)點(diǎn)
    • 搜索二叉樹的第K個(gè)節(jié)點(diǎn)
  • 重建(轉(zhuǎn)換)類

    • 根據(jù)中序和先序重建二叉樹 【字符串】
    • 轉(zhuǎn)化為雙向鏈表 【鏈表】
    • 序列化和反序列化 【字符串】

具備的基本能力

  • 二叉樹的前/中/后/層次遍歷
    • 遞歸
    • 非遞歸
  • 樹的相關(guān)概念的區(qū)別
    • 二叉樹 平衡二叉樹 二叉搜索樹 滿二叉樹 完整二叉樹
    • 高度 深度

1.打印類

22.從上往下打印二叉樹

從上往下打印出二叉樹的每個(gè)節(jié)點(diǎn),同層節(jié)點(diǎn)從左至右打印。

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};*/
class Solution {
public:
    vector<int> PrintFromTopToBottom(TreeNode* root) {
        
        vector<int> res; 
        if(!root) return res;
        
        queue<TreeNode*> queueNode;
        queueNode.push(root);
        
        while(queueNode.size()){
             TreeNode* pNode=queueNode.front();
             queueNode.pop();
             res.push_back(pNode->val);
            if(pNode->left) queueNode.push(pNode->left);
            if(pNode->right) queueNode.push(pNode->right);
                  
        }
        return res;
    }
};

60.把二叉樹打印成多行

從上到下按層打印二叉樹,同一層結(jié)點(diǎn)從左至右輸出。每一層輸出一行。

    /*
    struct TreeNode {
        int val;
        struct TreeNode *left;
        struct TreeNode *right;
        TreeNode(int x) :
                val(x), left(NULL), right(NULL) {
        }
    };
    */
    class Solution {
    public:
            vector<vector<int> > Print(TreeNode* root) {
                vector<vector<int>> res;
                if(!root) return res;
                
                queue<TreeNode*> q;
                q.push(root);
                
                while(q.size()){
                    int size=q.size();
                    vector<int> path;
                    for(int i=0;i<size;i++){
                        auto front=q.front();
                        path.push_back(front->val);
                        q.pop();
                        if(front->left) q.push(front->left);
                        if(front->right) q.push(front->right);
                     }
                     res.push_back(path);
                    
                }
                return res;
            
            }
        
    };

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

請(qǐng)實(shí)現(xiàn)一個(gè)函數(shù)按照之字形打印二叉樹,即第一行按照從左到右的順序打印,第二層按照從右至左的順序打印,第三行按照從左到右的順序打印,其他行以此類推

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
*/
class Solution {
public:
    vector<vector<int> > Print(TreeNode* p) {
        vector<vector<int>> res;
        vector<int> path;
        if(!p) return res;
        
        queue<TreeNode*> q;
        q.push(p);
        bool flag=true;
        // 加標(biāo)志位,奇數(shù)行 左->右  偶數(shù)行  右-> 左
       
        while(q.size()){
            
            //vector<int> path;
            int size= q.size();
            for(int i=0;i<size;i++){  
                //注意 這里  i<q.size()  不能這么寫 因?yàn)殛?duì)列是動(dòng)態(tài)變化的
                auto front=q.front();
                path.push_back(front->val);
                q.pop();
                if(front->left) q.push(front->left);
                if(front->right) q.push(front->right);     
               }
            if(!flag) reverse(path.begin(),path.end());
            flag=!flag;
            res.push_back(path);
            path.clear();
        
        }
        return res;

    }
    
};

2.性質(zhì)類

  • 對(duì)稱類

18.二叉樹的鏡像

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


/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};*/
class Solution {
public:
    void Mirror(TreeNode *pRoot) {
        if (pRoot==NULL || (pRoot->left== NULL && pRoot->right==NULL)){
            return;
        }
        TreeNode *temp=pRoot->left;
        pRoot->left=pRoot->right;
        pRoot->right=temp;
        if(pRoot->left){
            Mirror(pRoot->left);
        }
        if(pRoot->right){
            Mirror(pRoot->right);
        }
        return;
    }
};

58.對(duì)稱的二叉樹

請(qǐng)實(shí)現(xiàn)一個(gè)函數(shù),用來判斷一顆二叉樹是不是對(duì)稱的。注意,如果一個(gè)二叉樹同此二叉樹的鏡像是同樣的,定義其為對(duì)稱的

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
*/
class Solution {
public:
    
    bool isSymmetrical(TreeNode* p)
    {
         if(!p) return true;
         return dfs(p->left,p->right);
    }
    bool dfs(TreeNode * p,TreeNode * q ){
        if(!p || !q)  return  !p && !q ;  
        // 有一個(gè)為空,返回false,兩個(gè)都空的話返回 true
        if( p->val != q->val) return false;
        return dfs(p->left,q->right) && dfs(p->right,q->left);
    }

};
  • 平衡類

39.平衡二叉樹

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

class Solution {
public:
    bool ans = true;
    bool IsBalanced_Solution(TreeNode* p) {
        dfs(p);
        return ans;
    }
    int dfs (TreeNode* p){
        if (!p) return 0;
        int left = dfs(p->left),right=dfs(p->right);
        if (abs(left-right)>1) ans=false;
        return max(left,right)+1;
    };
};
  • 存在類

17.樹的子結(jié)構(gòu)

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

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};*/
class Solution {
public:
    bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
    {
        if(!pRoot1||!pRoot2)  return false;
        if(isPart(pRoot1,pRoot2)) return true;
        return HasSubtree(pRoot1->left,pRoot2)|| HasSubtree(pRoot1->right,pRoot2);
        //遞歸枚舉  先枚舉左邊 若沒有,再枚舉右邊
    }
    //判斷 第二棵數(shù)的點(diǎn)是不是在第一課樹上都有對(duì)應(yīng)的點(diǎn)
     bool isPart(TreeNode *p1,TreeNode *p2) {
         if(!p2) return true; // 第二課樹空了,說明之前的都匹配上了
         if(!p1||p1->val != p2->val) return false;
         return isPart(p1->left,p2->left) && isPart(p1->right,p2->right);
           }

};

23.二叉搜索樹的后續(xù)遍歷序列

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

class Solution {
public:
    vector<int> seq;
    
    bool VerifySquenceOfBST(vector<int> sequence) {
        if(sequence.empty()) return false;
        seq=sequence;
        return dfs(0,seq.size()-1);

    }
    bool dfs(int l, int r){
        if(l>=r) return true;
        int root = seq[r];
        int k=l;
        while(k<r && seq[k]< root) k++;
        for (int i= k;i<r;i++){
            if (seq[i]<root) return false;
        }
        return dfs(l,k-1)&& dfs(k,r-1);
    }
};

24.二叉樹中和為某一值的路徑

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

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};*/
class Solution {
public:
    vector<vector<int>> res;
    vector<int> path;
    vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
        
        if(!root || expectNumber <= 0) return res;
        dfs(root,expectNumber);
        return res;
    }
    void  dfs(TreeNode* p ,int sum)
    { 
        if(!p) return ;
        path.push_back(p->val);
        sum=sum-p->val;
        if(!p->left&&!p->right&&!sum) res.push_back(path);
        dfs(p->left,sum);
        dfs(p->right,sum);
        path.pop_back();
    }
};

3.參數(shù)類

38.二叉樹的深度

輸入一棵二叉樹,求該樹的深度。從根結(jié)點(diǎn)到葉結(jié)點(diǎn)依次經(jīng)過的結(jié)點(diǎn)(含根、葉結(jié)點(diǎn))形成樹的一條路徑,最長路徑的長度為樹的深度。

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};*/


class Solution {
public:
    int TreeDepth(TreeNode* p)
    {
        int res=0;
        if(!p) return res;
        
        queue<TreeNode*> q;
        q.push(p);
        
        while(q.size()){
            res++;
            int num = q.size();
            for(int i =0; i < num; i++){  // i<q.size() 不能這樣寫 因?yàn)槭莿?dòng)態(tài)變化的
                TreeNode* node=q.front();
                q.pop();
                if(node->left) q.push(node->left);
                if(node->right) q.push(node->right);   
            }
        }
            
        return res;  
    }
};

57.二叉樹的下一個(gè)結(jié)點(diǎn)

給定一個(gè)二叉樹和其中的一個(gè)結(jié)點(diǎn),請(qǐng)找出中序遍歷順序的下一個(gè)結(jié)點(diǎn)并且返回。注意,樹中的結(jié)點(diǎn)不僅包含左右子結(jié)點(diǎn),同時(shí)包含指向父結(jié)點(diǎn)的指針。

/*
struct TreeLinkNode {
    int val;
    struct TreeLinkNode *left;
    struct TreeLinkNode *right;
    struct TreeLinkNode *next;
    TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
        
    }
};
*/
class Solution {
public:
    TreeLinkNode* GetNext(TreeLinkNode* p)
    {
        if (p->right){ // 找右子樹左邊的那個(gè)
            p=p->right; 
            while(p->left){
                p=p->left;
            }
            return p;
        }
        while(p->next && p == p->next->right) p=p->next; 
        //進(jìn)不去的條件是找到了上面的第一個(gè)做左孩子的子節(jié)點(diǎn) 
        return p->next;
    }
};

62.二叉搜索樹的第K個(gè)結(jié)點(diǎn)

給定一棵二叉搜索樹,請(qǐng)找出其中的第k小的結(jié)點(diǎn)。例如, (5,3,7,2,4,6,8) 中,按結(jié)點(diǎn)數(shù)值大小順序第三小結(jié)點(diǎn)的值為4

class Solution {
public:
    TreeNode* KthNode(TreeNode* pRoot, int k)
    {   
        if(pRoot == NULL) return NULL;
        return dfs(pRoot,k) ;
    }
    
    TreeNode* dfs(TreeNode* pRoot, int& k)
    {
        TreeNode* target = NULL;
        if(pRoot->left !=NULL) 
            target = dfs(pRoot->left,k);
         k--;
         if(k==0){
            target = pRoot;
            return target;
         }
        if(target == NULL && pRoot->right !=NULL && k>0) 
            target = dfs(pRoot->right,k);
        return target;
    }
};

4.重建(轉(zhuǎn)換)類

4.重建二叉樹

輸入某二叉樹的前序遍歷中序遍歷的結(jié)果,請(qǐng)重建出該二叉樹。假設(shè)輸入的前序遍歷和中序遍歷的結(jié)果中都不含重復(fù)的數(shù)字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹并返回。

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
        if ( pre.empty()|| vin.empty()) return NULL;
        int root_val=pre[0];
        TreeNode *root=new TreeNode(root_val);
        int leftLength=0;
        int rightLength=0;
        for (int i=0;i<vin.size();i++)
        {
            if (vin[i]==root_val)
            {
                leftLength=i;
                rightLength=vin.size()-i-1;
                break;
            }
        }
        vector<int> in_left,in_right,pre_left,pre_right;
        for(int j=0;j<leftLength;j++)
        {
            in_left.push_back(vin[j]);
            pre_left.push_back(pre[j+1]);
        }
        for(int j=0;j<rightLength;j++)
        {
            in_right.push_back(vin[leftLength+1+j]);
            pre_right.push_back(pre[1+leftLength+j]);
        }
        root->left=reConstructBinaryTree(pre_left,in_left);
        root->right=reConstructBinaryTree(pre_right,in_right);
        return root;
    }
};

26.二叉搜索樹與雙向鏈表

輸入一棵二叉搜索樹,將該二叉搜索樹轉(zhuǎn)換成一個(gè)排序的雙向鏈表。要求不能創(chuàng)建任何新的結(jié)點(diǎn),只能調(diào)整樹中結(jié)點(diǎn)指針的指向

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};*/
class Solution {
public:
    TreeNode* Convert(TreeNode* root)
    {
        if(!root) return NULL;
        auto sides=dfs(root);
        return sides.first;
    }
    
    pair<TreeNode*,TreeNode*> dfs(TreeNode* root){
        
        if(!root->left&& !root->right) return {root,root};
        if(root->left&&root->right){
            auto lsides=dfs(root->left),rsides=dfs(root->right);
            lsides.second->right=root;root->left=lsides.second;
            rsides.first->left=root;root->right=rsides.first;
            return{lsides.first,rsides.second};
        }
        if(root->left){
            auto lsides=dfs(root->left);
            lsides.second->right=root,root->left=lsides.second;
            return{lsides.first,root};
        }
        if(root->right){
            auto rsides=dfs(root->right);
            root->right=rsides.first,rsides.first->left=root;
            return{root,rsides.second};
        }
    }
    
};

61.序列化二叉樹

請(qǐng)實(shí)現(xiàn)兩個(gè)函數(shù),分別用來序列化和反序列化二叉樹

二叉樹的序列化是指:把一棵二叉樹按照某種遍歷方式的結(jié)果以某種格式保存為字符串,從而使得內(nèi)存中建立起來的二叉樹可以持久保存。序列化可以基于先序、中序、后序、層序的二叉樹遍歷方式來進(jìn)行修改,序列化的結(jié)果是一個(gè)字符串,序列化時(shí)通過 某種符號(hào)表示空節(jié)點(diǎn)(#),以 ! 表示一個(gè)結(jié)點(diǎn)值的結(jié)束(value!)。

二叉樹的反序列化是指:根據(jù)某種遍歷順序得到的序列化字符串結(jié)果str,重構(gòu)二叉樹。

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
*/
class Solution {
public:
    char* Serialize(TreeNode *root) {    
        if(! root) return NULL;
        string str;
        dfs_s(root ,str); //注意函數(shù)的返回值
        char *res =new char[str.size()+1];
        int i;
        for(i=0;i<str.size();i++){
            res[i]=str[i];
        }
        res[i]='\0';
        return res;
    }
    
    void dfs_s(TreeNode *root,string &str){
        if(root==NULL){
            str+='#';
            return ;
        }
        str+=to_string(root->val);
        str+='!';
        dfs_s(root->left,str);
        dfs_s(root->right,str);
    }
    
    TreeNode* Deserialize(char *str) {
        if(str == NULL) return NULL;
        TreeNode* res=dfs_d(&str);
        return res;
    }
    
    TreeNode* dfs_d(char **str){
        if(**str == '#'){
            ++(*str);
            return NULL;
        }
        //把字符轉(zhuǎn)換成節(jié)點(diǎn)
        int num=0;
        while(**str!='\0' && **str != '!'){
            num=num*10+((**str)-'0');
            ++(*str);
        }
        TreeNode *root=new TreeNode(num);
        // 轉(zhuǎn)化完畢,查看是否還有未轉(zhuǎn)換的節(jié)點(diǎn)。
        // 到達(dá)字符串末尾即轉(zhuǎn)換完畢
        if(**str=='\0') return root;
        else (*str)++;
        root->left=dfs_d(str);
        root->right=dfs_d(str);
        return root;
    }
};
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容