加载中...

一些报错

1.error: non-void function 'inorderTraversal' should return a value [-Wreturn-type]
递归写法应该return什么,应该return一个vector?
2.no matching member function for call to 'push'
原因设置stack的类型为(treenode) 应该为(treenode*)

各种遍历

public:
    vector<int> inorderTraversal(TreeNode* root) {
        if (!root) {
            return;
        }

        vector<int> res;//建立要返回的数组
        inorder(root,res);//函数
        return res;//返回一个数组
    }
    void inorder(TreeNode* root,vector<int>&res ){
        if(!root) return ;//递归
        inorder(root->left,res);res.push_back(root->val);//中序
        inorder(root->right,res);

    }

前序非递归

void inorder(TreeNode* root,vector<int>&res ){
        stack<TreeNode*> s;
        s.push(root);
        while(!s.empty()){
            root=s.top();
            s.pop();
            res.push_back(root->val);//  如果是n叉树 就使用for(int i=root->children.size();i>=0;i--) 遍历children[i]          
            if(root->right) s.push(root->right);//先押入右结点再左 这样弹出就是先弹左结点
            if(root->left) s.push(root->left);
        }
   }

后序非递归

        stack<TreeNode*>s1;//两个数占 一个用来输出
        stack<TreeNode*>s2;
        s1.push(root); 
        while(!s1.empty()){
            root=s1.top();
            cout<<root->val;
            s2.push(root);
            s1.pop();if(root->left) s1.push(root->left);//先左后右
            if(root->right) {s1.push(root->right);}
        }
        while(!s2.empty()){
            res.push_back(s2.top()->val);
            s2.pop();
        }

中序非递归

//这里不需要提前放入head,否者会重复操作
stack<TreeNode*>s;
        while(!s.empty()||root){
            if(root)//无论是让root等于左子树还是右子树,都需要判断
            {
            s.push(root);
            root=root->left;
            }
            else{
            root=s.top();            //每次抽出栈,让这个root暂时保存
            res.push_back(root->val);
            s.pop();
            root=root->right;//让这个root等于右子树再遍历左子树
            }
        
        }

使用统一的迭代法

s.push(root);
        while(!s.empty()){
            root=s.top();
            if(root){
                s.pop();//看到了,但未处理,先抽出等下再翻进去
                if(root->right) s.push(root->right);
                s.push(root);s.push(nullptr);//这两句话一定不能变,变了就不对了!!
                //思路在每次null,则是要处理的root的时候压入数组,
                if(root->left) s.push(root->left);
            }else{//当看到null则是真正的
                s.pop();
                root=s.top();
                s.pop();
                res.push_back(root->val);
            }

树的层序遍历

vector<vector<int> >res;//定义一个vector 存放vector的数据 表示每一层 
if(!root) return res;
            queue<TreeNode*>q;
            q.push(root);
            while(!q.empty()){
                vector<int>cur;
                int size=q.size();//根据二叉树的性质,size记住当前队列还有的元素个数,用于抽出元素,当超过这个数据的时候
                for(int i=0;i<size;i++){//一层一层的来
                    root=q.front();
                    q.pop();//使用队列,先进先处理符合层序遍历
                    cur.push_back(root->val);//
                    if(root->left) q.push(root->left); //放左和放右
                    if(root->right) q.push(root->right); 

                }
                res.push_back(cur);//每一层都进行结算
            }
        return res;

树的右视图dfs法

 vector<int> rightSideView(TreeNode* root) {
        int depth=1;
         if(!root) return res;
        dfs(root,0);
        
    return res;
            }
    
    void dfs(TreeNode* root,int depth){
        if(!root) return ;
        if(depth==res.size()){//res里面存放的个数对应的是第几层 第一层就放第一个 永远放第一个
            res.push_back(root->val);当第一次发现depth,就放 ,放完res++,后面的depth不会满足所以进不了,实现首个的母的
        }
        depth++;//每次进入这个函数depth都会计数,木的是为了下面的dfs
        dfs(root->right,depth) ;
        dfs(root->left,depth) ;
    }
    

N叉树

class Node{
int val;
    vector<Node*> children;//用一个指针数组保存
}
vector<vector<int> >res;if(!root) return res;
        queue<Node* >q;
        q.push(root);
        while(!q.empty()){
            int size=q.size();
            vector<int>v ;
            for(int i=0;i<size;i++){
                root=q.front();
                q.pop();
                v.push_back(root->val);
                // s+=root->val;
                for(int i=0;i<root->children.size();i++)//这样做
                if(root->children[i]) q.push(root->children[i]);//使用下标
          
            }

            res.push_back(v);

        }return res;           

连接结点的下一个右侧节点

while(!q.empty()){
            int size=q.size();
            Node* pre;
            pre=q.front();            
            for(int i=0;i<size;i++){                
                Node* cur;//两个结点一个前,一个后
                if(i==0){cur=q.front();//取出每层首个结点
                    pre=q.front();
                }
                else{cur=q.front();//next指过去
                pre->next=cur;pre=pre->next;//走一步
                }                                
                q.pop();
                if(cur->left) q.push(cur->left);
                if(cur->right) q.push(cur->right);
                
                
                if(i==size-1){//当是最后一个的时候记得补上右节点为null
                    pre->next=NULL;
                }
            }

        }return root;

连接右结点递归版本

Node* connect(Node* root) {
        if(!root) return root;        
        if(root->left){//把下一层处理好
            root->left->next=root->right;
            if(root->next) root->right->next=root->next->left;//连接

        }
        connect(root->left);
        connect(root->right);//递归       
        return root;

        }

树的镜面对称(递归的比较使用)

bool cmp(TreeNode* left,TreeNode * right){//递归比较函数
//注意递归结束的条件
        if(!left&&!right) return true;//同时为空的时候也是真
        else if(!right||!left) return false;//当右边为空而左边不是的时候 false 100.00%
        
        else if(left->val!=right->val) return false;//注意做错[1,2,3]是因为少了这个没有处理值不相等的情况
        else{//还会有一种情况
            bool a=cmp(left->left,right->right);
            bool b=cmp(left->right,right->left);
            bool c=a&&b;
            return c;
        }

递归判断子树

bool isSubtree(TreeNode* root, TreeNode* subRoot) {
            if(cmp(root->left,subRoot)||cmp(root->right,subRoot))return false;//这样写不会递归;
bool isSubtree(TreeNode* root, TreeNode* subRoot) {
            // if(cmp(root->left,subRoot)||cmp(root->right,subRoot))return false;//这样写不会递归
            if(!root&&!subRoot) return true;
            if(!root||!subRoot) return false;
            if(cmp(root,subRoot))   return true;

            return isSubtree(root->left,subRoot)||isSubtree(root->right,subRoot);//判断不出来就继续递归!!!
        
    }
    bool cmp(TreeNode* p,TreeNode* q){一个比较函数
        if(!p&&!q) return true;//
        else if(!p||!q) return false;
        else if(p->val!=q->val) return false;
        else {
            
            return cmp(p->left,q->left)&&cmp(p->right,q->right );
        }

n叉树的深度

int getdepth(*node root)
if(!root) return 0;
        int m=0;
        for(int i=0;i<root->children.size();i++){
            
            m=max(m,getdepth(root->children[i]));//从左到右保存最大的就是
        }
        return m+1;//算上自本身

求树的节点个数 递归 看成将叶子结点也看成完全二叉树 o(logn)

 int countNodes(TreeNode* root) {//
if (root == nullptr) return 0;//关键!看懂这段代码首先设置只有一个结点的时候发现函数返回值是2<<0-1=1,所以后面都按这个走
        TreeNode* left = root->left;//好像只能这么简单所有left换成left->left不能换成
        TreeNode* right = root->right;
        int leftHeight = 0, rightHeight = 0; // 这里初始为0是有目的的,为了下面求指数方便
        while (left) {  // 求左子树深度,一直往左走,
            left = left->left;
            leftHeight++;
        }
        while (right) { // 求右子树深度,一直往右走
            right = right->right;
            rightHeight++;
        }
        if (leftHeight == rightHeight) {//当左边高度等于右边的时候,选一边进行 使用2
            return (2 << leftHeight) - 1; // 注意(2<<1) 相当于2^2,所以leftHeight初始为0,特判相当于简便了计算而不是递归求结点了
        }//左边不等于右边,各自分一个
        return countNodes(root->left) + countNodes(root->right) + 1;//如果右边没有,左边有会发现右边返回值是0

求深度可以从上到下去查 所以需要前序遍历(中左右)第一个是中,

而高度只能从下到上去查,所以只能后序遍历(左右中)最后一个是中,

判断完全二叉树

bool isBalanced(TreeNode* root) {
        if(!root) return true;        
        if(gethight(root)!=-1)
        return true;
        return false;   
    }
    int gethight(TreeNode *root){使用-1,始终保存-1 的值
        if(!root) return 0;//叶子节点
        int left=gethight(root->left);//左结点
        int right=gethight(root->right);//获取右结点的值
        if(left==-1) return -1;//当等于-1说明已经不是一个完全二叉树了 直接返回
        if(right==-1) return -1;
        if(abs(left-right)>1) return -1;//如果左边右边大于1说明不是二叉树 返回-1
        else return 1+max(right,left);//返回值是为了计算高度 +1算上了自己
    }

获得二叉树所有路径

vector<string> binaryTreePaths(TreeNode* root) {
            vector<string > res;
            vector<int >path;//两个vector 一个存入值一个存入答案
            if(!root) return res;
            traversal(root,path,res);
            return res;
    }
    void traversal(TreeNode * cur ,vector<int>&path ,vector<string>&res  ){
        path.push_back(cur->val);//中序遍历 进来先存入值
        if(!cur->left&&!cur->right){如果是叶子结点
            string s;
            for(int i=0;i<path.size()-1;i++){//为了让最后一个->符号合理
                s+=to_string(path[i]);
                s+="->";
            }
            s+=to_string(path[path.size()-1]);//使用string转话为数字的函数to_string(int val)
            res.push_back(s);
            return ;        }
        if(cur->left) {
        traversal(cur->left,path,res) ;path.pop_back();//回溯消去之前递归加入了那个值 
    }
    if(cur->right) {
        traversal(cur->right,path,res) ;path.pop_back();//使用pop back
    }
    }


递归精简版

void count(TreeNode *root,string path,vector &res){传值不是传引用防止了 错误
path+=to_string(root->val);
if(!root->left&&!root->right){
res.push_back(path);
return ;
}
if(root->left) {
count(root->left,path+"->",res) ;
}
if(root->right) {
count(root->right,path+"->",res) ;//使用path+->而不是path+= 否则会改变了
}
}

迭代

vector binaryTreePaths(TreeNode* root) {
stack<TreeNode > treest;//存迭代
stack pathst;//存string
vector res;//存值
if(!root) return res;
treest.push(root);
pathst.push(to_string(root->val));
while(!treest.empty()){
TreeNode
node =treest.top();treest.pop();//node 用于下面放置左右孩子
string path=pathst.top();pathst.pop();//用于存放string的值,不用在存入中结点也是这个理由
if(!node->left&&!node->right){
res.push_back(path);
}
if(node->right){
treest.push(node->right);
pathst.push(path+"->"+to_string(node->right->val));
}
if(node->left){
treest.push(node->left);
pathst.push(path+="->"+to_string(node->left->val));//传入的是path+“->”+值的这个字符串
}
}
return res;

统计左叶子节点之和: 首先你得知道怎么判断是不是左叶子结点 :只能通过该节点的父结点判断是不是叶子节点

  if(root->left&&!root->left>right&&!root->left->right

如果需要遍历整颗树,递归函数就不能有返回值。如果需要遍历某一条固定路线,递归函数就一定要有返回值!

找最后一层的左叶子的值


int maxlength=INT_MIN;//两个全局变量
    int value;
    int findBottomLeftValue(TreeNode* root) {
        travelsal(root,0);
        return value;
    }
    void travelsal(TreeNode* root,int leftlen){
        if(!root->left&&!root->right) if(leftlen>maxlength){//到达了叶子结点并且深度大于最大深度
            value=root->val;..更新值
            maxlength=leftlen;
        }
        if(root->left) travelsal(root->left,leftlen+1) ;//先左边后右边,自带回溯
        if(root->right) travelsal(root->right,leftlen+1);
        
    }

路经总和

bool hasPathSum(TreeNode* root, int targetSum) {
       if(dfs(root,targetSum)==-1) return true;//-1表示真
       return false;//    
    }
    int  dfs(TreeNode * root,int targetSum){
        if(!root) return 0;//
        targetsum-=root->val;//当减到0而且是叶子结点就好
        if(targetSum==0&&!root->left&&!root->right) return -1;//加完之后相等就return-1
        if(dfs(root->left,targetSum)==-1) return -1;//传值自带回溯
        if(dfs(root->right,targetSum)==-1) return -1;
        return 0;
    }  
bool haspathsum(treenode* root, int sum) {
        if (root == null) return false;
        if (!root->left && !root->right && sum == root->val) {//传入值 若值相等
            return true;
        }
        return haspathsum(root->left, sum - root->val) || haspathsum(root->right, sum - root->val);//,传的是相减的,只要有一边成功就可以
    }
bool hasPathSum(TreeNode* root, int targetSum) {
            if(!root) return false;
            stack<pair<TreeNode*,int> >s;//只要是pair都必须带个<元素类型,元素类型>
            s.push(pair<TreeNode*,int>(root,root->val) );

            while(!s.empty()){前序遍历
                pair<TreeNode*,int>node=s.top();s.pop();
                
                if(!node.first->left&&!node.first->right&&node.second==targetSum) return true;
                
                if(node.first->right) s.push(pair<TreeNode*,int>(node.first->right,node.second+node.first->right->val));
                if(node.first->left) s.push(pair<TreeNode*,int>(node.first->left,node.second+node.first->left->val));
            }
            return false;

vector<vector<int> >res;
    vector<int> path;//全局变量 path记录结点 常用
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
                if(!root) return res;
        path.push_back(root->val);//
        dfs(root ,targetSum-root->val);//传入一个根节点 传入一个值即可
        return res;
    }
    void dfs(TreeNode* root,int count){
            if(!root->left&&!root->right&&count==0) {//count==0,return
                res.push_back(path);return;
            }
            if(root->left){ path.push_back(root->left->val);
                dfs(root->left,count-root->left->val);
                path.pop_back();//记得放入和拿出path
            }
            if(root->right){
                path.push_back(root->right->val);
                dfs(root->right,count-root->right->val);
                path.pop_back();
            }return ;
    }

TreeNode* traversal (vector<int>& inorder, vector<int>& postorder) {

    // 第一步
    if (postorder.size() == 0) return NULL;//如果数组没有值说明已经没有了值,即空

    // 第二步:后序遍历数组最后一个元素,就是当前的中间节点或叶子节点
    int rootValue = postorder[postorder.size() - 1];//int 变量存中间结点的值,方便后面的建立,或者返回叶子结点
    TreeNode* root = new TreeNode(rootValue);//

    // 叶子节点
    if (postorder.size() == 1) return root;//数组元素只有上面这一个 说明是叶子结点可以直接return 

    // 第三步:找切割点
    int delimiterIndex;//分割点
    for (delimiterIndex = 0; delimiterIndex < inorder.size(); delimiterIndex++) {
        if (inorder[delimiterIndex] == rootValue) break;//在中序数组里面找,找到就直接退
    }

    // 第四步:切割中序数组,得到 中序左数组和中序右数组
    // 左闭右开区间:[0, delimiterIndex)
    vector<int> leftInorder(inorder.begin(), inorder.begin() + delimiterIndex);
    // [delimiterIndex + 1, end)//左闭右开 靠后面右边的不会包括
    vector<int> rightInorder(inorder.begin() + delimiterIndex + 1, inorder.end() );

    // 第五步:切割后序数组,得到 后序左数组和后序右数组
    //此时有一个很重的点,就是中序数组大小一定是和后序数组的大小相同的(这是必然)。
     // postorder 舍弃末尾元素,因为这个元素就是中间节点,已经用过了
    postorder.resize(postorder.size() - 1);//重新设置大小
  // 左闭右开,注意这里使用了左中序数组大小作为切割点:[0, leftInorder.size)//
    vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size());//迭代器加数字
    // [leftInorder.size(), end)
    vector<int> rightPostorder(postorder.begin() + leftInorder.size(), postorder.end());//不用+1因为需要这个数

    // 第六步
    root->left = traversal(中序左数组, 后序左数组);//递归
    root->right = traversal(中序右数组, 后序右数组);//

    return root;
} 

```上面的优化 就是递归的时候传引用 然后 定义几个数组 保存各个边界从而达到不多次使用vector的效果

##使用直接传引用数组的话 利用下表索引 从14->92 的击败时间

TreeNode* constructMaximumBinaryTree(vector& nums) {

return     dfs(nums,0,nums.size());
}
TreeNode* dfs(vector<int> &v ,int left,int right ){      
        if(left>=right) return nullptr;
        // if(v.size()==1) return new TreeNode(v[0]);
        int p=left;

        for(int i=left+1;i<right;i++){
            if(v[p]<v[i]) {
                p=i;
            }   
        }   
        TreeNode * node=new TreeNode(v[p]);

        node->left=dfs(v,left,p);
        node->right=dfs(v,p+1,right);

        return node;
}

##合并二叉树

class Solution {
public:
TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
if (t1 == NULL) return t2;
if (t2 == NULL) return t1;
queue<TreeNode> que;
que.push(t1);//要押入一起压入
que.push(t2);
while(!que.empty()) {
TreeNode
node1 = que.front(); que.pop();
TreeNode* node2 = que.front(); que.pop();//要压入一起压入,要处理一起处理,但栈的抽出之后不会影响树的任何东西
// 此时两个节点一定不为空,val相加
node1->val += node2->val;//以左边的树为基准,改变他的东西,相当于一次处理一个结点,虽然弄了两次
//结点上面的部分已经处理好了,不需要再看一下了,下面已经是对子树的处理了

        // 如果两棵树左节点都不为空,加入队列
        if (node1->left != NULL && node2->left != NULL) {//因为两个左树都不为空,所以要处理一下,让两个子树进去
            que.push(node1->left);
            que.push(node2->left);
        }
        // 如果两棵树右节点都不为空,加入队列
        if (node1->right != NULL && node2->right != NULL) {//因为两个右边的树不为空,所以要处理下,让两个右边进去
            que.push(node1->right);
            que.push(node2->right);
        }

        // 当t1的左节点 为空 t2左节点不为空,就赋值过去
        if (node1->left == NULL && node2->left != NULL) {
            node1->left = node2->left;//因为有空的 ,所以直接弄就好了,不需要使用队列
        }
        // 当t1的右节点 为空 t2右节点不为空,就赋值过去
        if (node1->right == NULL && node2->right != NULL) {
            node1->right = node2->right;//因为有空的 ,直接弄,并不需要队列,不需要传入
        }
    }
    return t1;//将tree1作为了答案
}

};

```注意:只是做左边的值的修改!!
TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
        if(!root1) return root2;if(!root2) return root1;//如果一个为空就返回另一个,如果另一个也为空也是满足的
        root1->val+=root2->val;//将值相加
        root1->left=mergeTrees(root1->left,root2->left);//继续传入双方的左边
        root1->right=mergeTrees(root1->right,root2->right);
        return root1;
    }
posted @ 2021-12-05 17:19  liang302  阅读(33)  评论(0编辑  收藏  举报