剑指offer 菜鸡划水的二叉树总结1

(1)重建二叉树

上来就想递归就完事儿了

 

 

/**
 * 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.size()||!vin.size())return NULL;
        int root=pre[0];
        TreeNode * RootNode=new TreeNode(pre[0]);
        
        auto vinroot=find(vin.begin(),vin.end(),root);
        int lsize=vinroot-vin.begin();
        int rsize=vin.end()-vinroot-1;
        TreeNode* left=reConstructBinaryTree(vector<int>(pre.begin()+1,pre.begin()+1+lsize),
                                            vector<int>(vin.begin(),vin.begin()+lsize));
        TreeNode* right=reConstructBinaryTree(vector<int>(pre.begin()+1+lsize,pre.end()),
                                            vector<int>(vinroot+1,vin.end()));
        RootNode->left=left;
        RootNode->right=right;
                                              return RootNode;
        
    }
};

(2)二叉树的镜像

/*
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) return;
        Mirror(pRoot->left);
        Mirror(pRoot->right);
        TreeNode * temp=pRoot->left;
        pRoot->left=pRoot->right;
        pRoot->right=temp;
    }
};

一般来说这里用递归是显而易见的,但有时候面试官想考我们对于代码的转化能力,让把这个递归转化为非递归怎么办?

/*
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) return;
        queue<TreeNode *>que;
        TreeNode* temp;
        que.push(pRoot);
        while(!que.empty())
        {
            temp=que.front()->left;
            que.front()->left=que.front()->right;
            que.front()->right=temp;
            if(que.front()->left)
            que.push(que.front()->left);
            if(que.front()->right)
            que.push(que.front()->right);
            que.pop();
        }
    }
};

希望我的脑子可以转一转  啥时候都判断一下是不是NULL,真是三天两头错这种憨憨东西

(3)二叉树的后续遍历

每次看到二叉树就觉的指定又是递归,所以我们先按递归写一遍再说..

首先你要知道树可以空 二叉树不能空......我吐了我  二叉树不能看做树的分支  不是被包含的关系.因此

class Solution {
public:
    bool judge(vector<int> seq,int start,int end){
        if(start>=end)return true;
        int k;
        for(k=start;seq[k]<seq[end];k++)
        {
            
        }
        for(int j=k;j<=end;j++)
        {
            if(seq[j]<seq[end])return false;
        }
        return judge(seq,start,k-1)&&judge(seq,k,end-1);
        
    }
    bool VerifySquenceOfBST(vector<int> sequence) {
        int len=sequence.size();
        if(len<=0)return false;
        if(len==1)return true;
        return judge(sequence,0,len-1);
    }
};

这里我写的代码非常的恶心,不建议大家这么写.我照着王小明同学的又写了一遍.

class Solution {
public:
   
    bool VerifySquenceOfBST(vector<int> sequence) {
        int len=sequence.size();
        if(len==0)return false;
        if(len==1)return true;
        int k=0;
        while(k<len&&sequence[k]<sequence[len-1])k++;
        for(int j=k;j<len;j++)
        {
            if(sequence[j]<sequence[len-1])return false;
        }
        bool a=true,b=true;
        if(k>0)a=VerifySquenceOfBST(vector<int>(sequence.begin(),sequence.begin()+k));
        if(k<len-1)b=VerifySquenceOfBST(vector<int>(sequence.begin()+k,sequence.end()-1));
        return a&&b;
    }
};

小明同学的代码写的真的很优雅....

之后是一个大佬提出的加入上下限优化时间复杂度的方法  我大概知道啥意思 但我并不想写   一会看看这里要不要补好了....

//这里好像要补一个代码//

(4)二叉树中和为某一值的路径

这个题我们先整一个递归的写法

/*
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> > ans;
    vector<int> tempans;
    vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
        if(root==NULL)return ans;
        expectNumber-=root->val;
        tempans.push_back(root->val);
        if(root->left==NULL&&root->right==NULL&&0==expectNumber)ans.push_back(tempans);
        if(root->left)
        {
            FindPath(root->left,expectNumber);
        }
        if(root->right)
        {
            FindPath(root->right,expectNumber);
        }
        tempans.pop_back();
        return ans;
    }
};

然后要整一个非递归的写法,思想就是深度优先遍历这颗树就好咯,可以拿一个栈来,然后有子节点就丢进去判断.....不想写了,算求

(5)二叉搜索树与双向链表

/*
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* pRootOfTree)
    {
        if(pRootOfTree==NULL)return NULL;
        TreeNode * left=Convert(pRootOfTree->left);
        TreeNode * right=Convert(pRootOfTree->right);
        TreeNode * temp=left;
        while(left&&left->right)
        {
            left=left->right;
        }
        pRootOfTree->left=left;
        pRootOfTree->right=right;
        if(right)right->left=pRootOfTree;
        if(left){
            left->right=pRootOfTree;
            return temp;
        }
        return pRootOfTree;
    }
};

emmm这个好像做了好几遍了.

看了一眼题解.好像有一种朴素做法是中序遍历这个搜索树  然后存起来,挨个改变左右指针就完事儿了

(6)二叉树的深度

我的理解中这个题是给下一个题作铺垫的

首先想到的一定是递归啦....

/*
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* pRoot)
    {
        if(pRoot==NULL)return 0 ;
        return max(TreeDepth(pRoot->left),TreeDepth(pRoot->right))+1;
    }
};

看题解.  有人用层遍历写了球深度,有时候是这样的  把简单的问题想复杂,这样以后遇到复杂的问题就能很快的联系到简单的问题.....那么我们写一下层遍历获取深度.

/*
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* pRoot)
    {
        if(pRoot==NULL)return 0 ;
        queue<TreeNode*> que;
        int len=0;
        int size=1;
        que.push(pRoot);
        while(size!=0&&!que.empty())
        {
            size--;
            TreeNode * temp=que.front();que.pop();
            if(temp->left)que.push(temp->left);
            if(temp->right)que.push(temp->right);
            if(size==0)
            {
                len++;
                size=que.size();
            }
        }
        return len;
    }
};

最近的记忆里真是有够烂的,一截简单的代码老是自己放坑...我是憨憨..如果当年没有好好学习去搞电竞,说不定....打不过别人也能做主播呢.2333 

(7)平衡二叉树

这里就是判断左右的深度差距...把刚刚的获得深度的方法拿来.简简单单就过了....说起来,二叉树可不可以为空只是一个概念问题,可能要视情况而定了2333333

class Solution {
public:
    int getDeep(TreeNode* pRoot)
    {
        if(pRoot==NULL)return 0;
        return 1+max(getDeep(pRoot->left),getDeep(pRoot->right));
    }
    bool IsBalanced_Solution(TreeNode* pRoot) {
        if(pRoot==NULL)return true;
        if(abs(getDeep(pRoot->left)-getDeep(pRoot->right))<=1&&IsBalanced_Solution(pRoot->left)&&IsBalanced_Solution(pRoot->right))return true;
        return false;
    }
};

嗯  这里其实是可以剪枝的..但好像也没啥必要....

(8)二叉树的下一个结点

/*
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:
    queue<TreeLinkNode*> que;
    void zhongxubianli(TreeLinkNode* pNode){
        if(pNode==NULL)return;
        zhongxubianli(pNode->left);
        que.push(pNode);
        zhongxubianli(pNode->right);
    }
    TreeLinkNode* GetNext(TreeLinkNode* pNode)
    {
        if(pNode==NULL)return pNode;
        TreeLinkNode * p=pNode;
        while(p->next)p=p->next;
        zhongxubianli(p);
        while(!que.empty())
        {
            TreeLinkNode * temp=que.front();que.pop();
            if(temp==pNode)
            {
                if(!que.empty())return que.front();
                return NULL;
            }
        }
    }
};

就是简单的找到头  然后就中序遍历存到队列中,找到这个节点,访问下一个节点就行了

 

看题解.有大佬有空间复杂度O1的方法  就是直接找,当有右节点 下一个是右边的最左节点  当无右节点,是父亲的左节点,那就访问父亲节点就行,当是父亲的右节点.找父亲的父亲节点,直到找到作为某节点左节点的祖先  就是咯

/下次补代码/

(8)对称的二叉树

 

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
*/
class Solution {
public:
    bool judge(TreeNode* p1,TreeNode* p2)
    {
        if(p1==NULL&&p2==NULL)return true;
        if(!p1||!p2)return false;
        if(p1->val!=p2->val)return false;
        
        return judge(p1->left,p2->right)&&judge(p1->right,p2->left);
    }
    bool isSymmetrical(TreeNode* pRoot)
    {
        if(pRoot==NULL)return true;
        if(judge(pRoot->left,pRoot->right))return true;
        return false;
    }

};

这里我依然打算分享一种非递归的算法,这样可以很快的提高代码能力

/下次补/

9.之字形打印二叉树

心态日常爆炸,一看到这个就能想起字节的HR的无奈...很对不起他,字节的面试真的做的很好,不管是回馈的速度,面试通知什么什么,还有面试的时候hr的态度都给人一种,我们是在交流的感觉,这里我想diss某企 hr面试=怼人,纯粹像是我抢你饭碗一样.....

这里先给出我后来自己做的第一版的代码,用了两个栈来避免考虑偶数层逆序输出的问题.非常滴银鑫 黑好用

/*
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* pRoot) {
        vector<vector<int> > ans;
        if(pRoot==NULL)return ans;
        stack<TreeNode*> sta1;
        stack<TreeNode*> sta2;
        sta1.push(pRoot);
        int x=0;
        int index=0;
        
        
        
        while(!sta1.empty()||!sta2.empty())
        {vector<int> tempvec;
            index=0;
            if(!sta1.empty())
            {
                while(!sta1.empty())
            {
                TreeNode* temp=sta1.top();
                    
                tempvec.push_back(temp->val);
                if(temp->left)
                sta2.push(temp->left);
                if(temp->right)
                sta2.push(temp->right);
                sta1.pop();
            }
            }
            else
            {
                while(!sta2.empty())
            {
                TreeNode* temp=sta2.top();
                tempvec.push_back(temp->val);
                if(temp->right)
                sta1.push(temp->right);
                if(temp->left)
                sta1.push(temp->left);
                sta2.pop();
            }
            }
            
            if(!tempvec.empty())
            {
                ans.push_back(tempvec);
         tempvec.clear();
            }
         
            x++;
                
        }
        return ans;
    }
    
};

然后我们这里做一种稍微普遍一点的做法,用一个变量标识当前层应该如何放入结果中就可以咯

/*
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* pRoot) {
        vector<vector<int> > ans;
        vector<int> tempans;
        vector<int> temptempans;
        if(pRoot==NULL)return ans;
        queue<TreeNode *>que;
        int label=0;
        int size=1;
        que.push(pRoot);
        while(!que.empty()&&size)
        {
            temptempans.clear();
            while(size--)
            {
                TreeNode * temp=que.front();que.pop();
                if(temp->left)que.push(temp->left);
                if(temp->right)que.push(temp->right);
                temptempans.push_back(temp->val);
            }
            if(label==0){ans.push_back(temptempans);}
            if(label==1){
                tempans.clear();
                for(int i=0;i<temptempans.size();i++)tempans.insert(tempans.begin(),temptempans[i]);
                ans.push_back(tempans);
            }
            label^=1;
            size=que.size();
        }
        return ans;
        
    }
    
};

这里我依旧写的非常的愚蠢   不知道为什么看起来特别的不清晰,让我们康康题解.发现题解的老哥用了双端队列,避免了我们想啥子一样把一个中间答案转来转去.

(10)把二叉树打印成多行

....我猜这俩题顺序整反了,我人傻了.反正多写总是没错的...让我们再写一遍好了.....

/*
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* pRoot) {
            vector<vector<int> >ans;
            vector<int> tempans;
            if(pRoot==NULL)return ans;
            queue<TreeNode *> que;
            que.push(pRoot);
            int size=1;
            while(!que.empty())
            {
                tempans.clear();
                while(size--)
                {
                    TreeNode * top=que.front();que.pop();
                    if(top->left)que.push(top->left);
                    if(top->right)que.push(top->right);
                    tempans.push_back(top->val);
                }
                ans.push_back(tempans);
                size=que.size();
            }
            return ans;
        }
    
};

(11) 序列化二叉树

序列化应该大家都听过,也知道是什么意思,但是第一次写还是有点迷茫,因为要返回一个char类型的指针感觉会很麻烦......然后就  嫖题解就完事儿了0.0

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
*/
class Solution {
public:
    vector<int> buf;
    void dfs(TreeNode * p)
    {
        if(p==NULL){buf.push_back(0x7fffffff);return;}
        buf.push_back(p->val);
        dfs(p->left);
        dfs(p->right);
    }
    TreeNode* dfs2(int *&p)
    {
        if(*p==0x7fffffff){p++;return NULL;}
        TreeNode* node=new TreeNode(*p);
        ++p;
        node->left=dfs2(p);
        node->right=dfs2(p);
        return node;
    }
    char* Serialize(TreeNode *root) {    
        buf.clear();
        dfs(root);
        int * res=new int[buf.size()];
        for(int i=0;i<buf.size();i++)res[i]=buf[i];
        return (char *)res;
    }
    TreeNode* Deserialize(char *str) {
        int * p=(int *)str;
        return dfs2(p);
    }
};

 

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