树的相关题目

五.树

5.1二叉树的遍历 分别写出递归和迭代版本*

5.1.1.先序优先遍历 Binary Tree Preorder Traversal

递归版本

class Solution {
public:
    vector<int> preorderTraversal(TreeNode *root) {
        vector<int > ret;
        helper(ret,root);
        return ret;
    }

    void helper(vector<int>&ret , TreeNode* root){
        if(root==NULL)return ;
        else 
        ret.push_back(root->val);
        if(root->left!=NULL)
          helper(ret,root->left);
        if(root->right!=NULL)
        helper(ret,root->right);
    }
};

迭代版本

class Solution {
public:
    vector<int> preorderTraversal(TreeNode *root) {
        //用栈来实现先序优先遍历
        vector<int > ret;
        if(root==NULL) return ret;
        stack<TreeNode* > mystack;
        mystack.push(root);
        TreeNode* temp;
        while(!mystack.empty()){
             temp= mystack.top();
             mystack.pop();

             ret.push_back(temp->val); //先把右子节点入栈
             if(temp->right!=NULL)
               mystack.push(temp->right);
             if(temp->left!= NULL)
               mystack.push(temp->left);
        }
        return ret;
    }
};
5.1.2中序优先遍历

递归版本

class Solution {
public:
    vector<int> inorderTraversal(TreeNode *root) {
        vector<int >  ret;
        helper(ret, root);
        return ret;
    }
    void helper(vector<int>&ret ,TreeNode* root){
        if(root==NULL) return;
        if(root->left!=NULL)
           helper(ret,root->left);
        ret.push_back(root->val);
        if(root->right!=NULL)
         helper(ret,root->right);
    }
};

迭代版本

 class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {

        vector<int> ret;
        if(root==NULL) return ret;
        stack<TreeNode* > mystack;
        TreeNode* p=root;
        while(p!=NULL){
          mystack.push(p);
          p=p->left;
        }

        while(!mystack.empty()){
           TreeNode * temp = mystack.top();
           mystack.pop();
           ret.push_back(temp->val);
           if(temp->right!=NULL){ //如果出栈的节点右子节点不空,这将右子节点的左子节点入入栈,直到没有左子节点
               p=temp->right;
               while(p!=NULL){
               mystack.push(p);
               p=p->left;
               }
           }
        }
        return ret;
    }
};
5.1.3 后序优先遍历
  • 思考

  • 步骤

      1. 1.


      1. 3.
  • 注意
5.1.4 输出二叉树的每层的数。 leetcode 102
  • 思考
    递归版本,相当于广度优先遍历,用一个参数来表明大小

  • 步骤

      1. 1.


      1. 3.
  • 注意
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int> > ret;
        if(root==NULL)
           return ret;
        helper(root, ret,0);
        return ret; 
    }

    void helper(TreeNode* root, vector<vector<int> > &ret,int level){

        if(!root)return ;

        if(level+1>ret.size() ) //注意 level>ret.size()-1    unsigned int 与 int 运算时, int 会被转换为unit
             ret.push_back(vector<int>());
        ret[level].push_back(root->val);

        if(root->left!=NULL)
             helper(root->left, ret ,level+1);
        if(root->right!=NULL)
        helper(root->right, ret,level+1);
    }
};

class Solution {
public:
    vector<vector<int> > levelOrder(TreeNode* root) {
        vector<vector<int> > ret;
        if(root==NULL)
           return ret;
        vector<TreeNode* >  layer;

       layer.push_back(root);
        while(!layer.empty()){  
            vector<int> temp;
            vector<TreeNode* > deq;
            TreeNode* t;
            for(int i=0 ;i<layer.size();i++){
                 t= layer[i];
                 temp.push_back(t->val);
                 if(t->left)
                 deq.push_back(t->left);
                 if(t->right)
                  deq.push_back(t->right);
            }
            ret.push_back(temp);
            layer=deq;
        }
        return ret; 
    }
};




class Solution {
public:
    vector<vector<int> > levelOrder(TreeNode* root) {
        vector<vector<int> > ret;
        if(root==NULL)
           return ret;
        deque<TreeNode* > deq1;
        deque<TreeNode* > deq2;

        deq1.push_back(root);
        while(!deq1.empty())
        {  
            vector<int> temp;
            TreeNode* t;
            while(!deq1.empty()){
                 t=deq1.front();
                 deq1.pop_front();
                 temp.push_back(t->val);
                 if(t->left)
                  deq2.push_back(t->left);
                 if(t->right)
                  deq2.push_back(t->right);
            }
            ret.push_back(temp);
            swap(deq1,deq2);  //这个知识交换指向的空间,并没有复制操作
        }
        return ret; 
    }
};
5.1.5 返回二叉树每层最右边的节点

结果同上:

//只不过是
//result[i]=root->val; 不断根新最后一个数存放的数组
class Solution {
public:
    vector<int> rightSideView(TreeNode* root) {

        vector<int> ret;
        vector<TreeNode* > layer;
        if(root==NULL) return ret;
        layer.push_back(root);
        int level=0;
        while(!layer.empty()){
            vector<TreeNode* > temp;
            for(int i=0;i<layer.size();i++){
                TreeNode*  p=layer[i];
                if(level+1>ret.size())
                    ret.resize(level+1);
                ret[level]=layer[i]->val;
                if(p->left!=NULL)
                   temp.push_back(p->left);
                 if(p->right!=NULL)
                   temp.push_back(p->right);
            }
            layer=temp;
            level++;
        }
        return ret;
    }
};

5.2树的判定

5.2.1 两个树是否相等
  • 思考
    Given two binary trees, write a function to check if they are equal or not.

Two binary trees are considered equal if they are structurally identical and the nodes have the same value.

  • 步骤
      1. 1.


      1. 3.
  • 注意
 class Solution {
 /* 1.如果其中之一NULL,则该判断另一个子树是否为NULL
  * 2.当前两值是否相等,递归判定其左右子树
  */
public:
    bool isSameTree(TreeNode* p, TreeNode* q) {
        if(p==NULL) return q==NULL;
        if(q==NULL) return p==NULL;
        return p->val==q->val&&isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
    }
};

//非递归版本 借用栈来实现
class Solution {
public:
    bool isSameTree(TreeNode* p, TreeNode* q) {


         if(p==NULL)return q==NULL;
         if(q==NULL) return p==NULL;
         stack<TreeNode* > stk;
         stk.push(q);
         stk.push(p);


        while(!stk.empty())
        { 
            p=stk.top();
            stk.pop();
            q=stk.top();
            stk.pop();
            if(p==NULL&&q==NULL) continue;
            if(p==NULL||q==NULL) return false;

            if(p->val!=q->val) return false;
             stk.push(q->right);
             stk.push(p->right);
             stk.push(q->left);
             stk.push(p->left);
        }

        return true;
    }
};
5.2.2 判断树是否对称
- **思考**:


 - **步骤**:
    * 1. 
    * 2. 
         *   
         *   
         *   
    * 3. 
 - **注意**:
class Solution {
public:
    bool isSymmetric(TreeNode *root) {
        if(root==NULL) return true;
        return helper(root->left,root->right);
    }
    bool helper(TreeNode * p, TreeNode * q){
        if(p==NULL) return q==NULL;
        if(q==NULL)  return p==NULL;
       return p->val==q->val&&helper(p->left,q->right)&&helper(p->right,q->left);
    }
};



// 非递归版本
class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        if(!root) return true;
        return isSymmetric(root->left, root->right);
    }
     bool isSymmetric(TreeNode* p, TreeNode* q) {
        if(!p&&!q) return true;

        stack<TreeNode* > stk;
        stk.push(q);
        stk.push(p);
        while(!stk.empty()){ 
            p=stk.top();
            stk.pop();
            q=stk.top();
            stk.pop();
            if(!p&&!q) continue;
            if(!p||!q) return false;
            if(p->val!=q->val) return false;

             stk.push(q->right);
             stk.push(p->left);
             stk.push(q->left);
             stk.push(p->right);
        }

        return true;
    }
};
5.2.3 二叉树是否平衡 Validate Binary Search Tree

Given a binary tree, determine if it is height-balanced.

For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differ by more than 1.

class Solution {
public:
    bool isBalanced(TreeNode *root) {

        int height = getHeight(root);
        if(height==-1)
           return false;
        return true;
    }

    int getHeight(TreeNode * root) {
        if(root==NULL) return 0;

        int left = getHeight(root->left);
        int right =getHeight(root->right);

        if(left==-1||right==-1||abs(left-right)>1) return -1;
        return  max(left,right)+1;
    }
};
5.2.4 二叉搜索树是否合法 Validate Binary Search Tree

Description :
Given a binary tree, determine if it is a valid binary search tree (BST).
Assume a BST is defined as follows:

The left subtree of a node contains only nodes with keys less than the node’s key.
The right subtree of a node contains only nodes with keys greater than the node’s key.
Both the left and right subtrees must also be binary search trees.

思考: 中序遍历,当前值大于中序遍历的last 值,全部成立即可,那么怎么获取中序遍历的最后一个之呢,使用引用

class Solution {
public:
    bool isValidBST(TreeNode* root) {
        if(root==NULL)
          return true;
          bool mark=true;
         int last=0;
          help(root,mark,last);
    }
    bool help(TreeNode* root, bool& first, int &last){
        if(root==NULL) return true;

        bool templeft = help(root->left,first,last);  // 遍历左子树,同时返回遍历的最后一个值

        if(!templeft) return false;   // 左子树不合法,则返回false

        if(first){                  // 当前节点是第一个值,这不比较
            first=false;
        } else if(last>=root->val)         // 不是第一个节点则比较
           return false;  

        last = root->val;                //更新已遍历的最后一个值
        return help(root->right,first,last); // 遍历右子树

    } 
};

5.3 树的路径与深度

5.3.1 二叉树的最小深度 letcode 111 Minimum Depth of Binary Tree

Description:
Given a binary tree, find its minimum depth.

The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.
思考:
1.二叉树的广度优先遍历,利用队列,直到找到一个叶子节点,则停止循环。
2.递归的解法: 只有叶子节点才算深度,如果为叶子节点,则返回1,如果非叶子节点,但其中左右子树为NULL,则返回另一个为空的子树的深度,若左右子树都不为NULL,则返回两者中小的+1;

class Solution {
public:
    int minDepth(TreeNode* root) {

        if(root==NULL) return 0;

        if(root->left==NULL&&root->right==NULL) return 1;

        if(root->left==NULL)return minDepth(root->right)+1;
        if(root->right==NULL) return minDepth(root->left)+1;

       return min(minDepth(root->left),minDepth(root->right))+1;

    }
};

class Solution {
public:
    int minDepth(TreeNode* root) {
        if(root==NULL)return 0;
        vector<TreeNode* > vec;
        vec.push_back(root);
        int ret=0;
        while(!vec.empty()){
            ret++;
            vector<TreeNode* >temp;
            for(int i=0;i<vec.size();i++){
             if(vec[i]->left!=NULL)
                    temp.push_back(vec[i]->left);
             if(vec[i]->right!=NULL)
                 temp.push_back(vec[i]->right);
             if(vec[i]->left==NULL&&vec[i]->right==NULL)
                return ret;
            }
            vec=temp;
        }
        return ret;
    }
};
5.3.2 二叉树的最大高度 leetcode 104
class Solution {
public:
    int maxDepth(TreeNode* root) {
        if(root==NULL)return 0;
        return max(maxDepth(root->left),maxDepth(root->right))+1;
    }
};
5.3.3 是否存在和为定值的路径 leetcode 112

Description:
Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.

For example:
Given the below binary tree and sum = 22,
5
/ \
4 8
/ / \
11 13 4
/ \ \
7 2 1
return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22.

class Solution {
public:
    bool hasPathSum(TreeNode *root, int sum) {

        if(root==NULL) return false;
        if(root->left==NULL&&root->right==NULL) {
            if(sum==root->val)
             return true;
             else return false;
        }
       return hasPathSum(root->left,sum-root->val)||
       hasPathSum(root->right,sum-root->val);
    }

};
5.3.4 Binary Tree Maximum Path Sum leetcode 124
class Solution {
public:
    int maxPathSum(TreeNode* root) {

        if(root==NULL) return 0;
       int  m=root->val;
        getSum(root,m);
        return m;
    }

    int getSum(TreeNode * root ,int &m){
        if(root==NULL) return 0;

        int left = getSum(root->left,m);
        int right =getSum(root->right,m);

        int ret =max(max(left ,right),0)+root->val;  //经过当前节点的长路径,左,右,仅有当前节点
        m=max(max(ret,m),left+right+root->val);      // 横跨当前节点的最长路径

        return ret;
    }

};

5.4 树的构造与变换

5.4.1 Flatten Binary Tree to Linked List

实际上的先序遍历变为链表


class Solution {
public:
    void flatten(TreeNode* root) {
        if(root==NULL) return ;
        stack<TreeNode* > stk;
        stk.push(root);
        TreeNode te(0);
        TreeNode* dummy=&te;
        TreeNode* tail=dummy;

        TreeNode * current;
        while(!stk.empty()){
            current =stk.top();
            stk.pop();

            if(current->right)
            stk.push(current->right);
            if(current->left)
            stk.push(current->left);

            tail->right=current;
            tail=current;
            tail->left =NULL;
            tail->right =NULL;

        }

        root=dummy->right;
    }
};
5.4.2 Populating Next Right Pointers in Each Node
 - **思考**:
 1.立即想到使用广搜,记录每一层的链表尾节点,但需要有一个 vector<TreeLinkNode* >  来记录每一层的尾节点,不符合题目的常数空间的要求
 2. 递归调用,对每一层已经链接好的链表,遍历其中每个节点,操纵他们的子节点
  • 步骤
      1. 1.


      1. 3.
  • 注意
// 采用广度优先遍历的思想
class Solution {
public:
    void connect(TreeLinkNode *root) {
    vector<TreeLinkNode* > ret;
    helper(root, ret,0);
}
void helper(TreeLinkNode* root , vector<TreeLinkNode* > &ret, int level){
    if(root==NULL) return;
    if(level+1>ret.size())
      ret.push_back(root);
    else{  
      ret[level]->next=root;
      ret[level]=root;
    }

    helper(root->left ,ret,level+1);
    helper(root->right, ret,level+1);
  }
};

class Solution {
public:
    void connect(TreeLinkNode *root) {

        if(root==NULL||root->left==NULL) return;
        TreeLinkNode* p=root;
        TreeLinkNode* tail=root->left;  //下一层链表的队尾
        while(p!=NULL){
            if(p==root){
               p->left->next =p->right;
            }
            else {
                tail->next=p->left;
                p->left->next =p->right;
            }
            tail =p->right;
            p=p->next;
        }
        connect(root->left);
    }
};
5.4.3 Populating Next Right Pointers in Each Node II

class Solution {
public:
    void connect(TreeLinkNode *root) {
        vector<TreeLinkNode* > ret;
        helper(root, ret,0);
    }
    void helper(TreeLinkNode* root , vector<TreeLinkNode* > &ret, int level){
        if(root==NULL) return;
        if(level+1>ret.size())
          ret.push_back(root);
        else{  
          ret[level]->next=root;
          ret[level]=root;
        }

        helper(root->left ,ret,level+1);
        helper(root->right, ret,level+1);

    }
};

//递归版本
class Solution {
public:
    void connect(TreeLinkNode *root) {

        if(root==NULL) return;
        TreeLinkNode* p=root;

         TreeLinkNode temp(0);
         TreeLinkNode* tail=&temp;
        while(p!=NULL){
             if(p->left==NULL&&p->right==NULL){
               p=p->next;
               continue;
             }
            else if(p->left!=NULL&&p->right!=NULL){
                 tail->next =p->left;
                 p->left->next=p->right;
                 tail=p->right;
            }
            else {
                tail->next = (p->left!=NULL)?p->left:p->right;
                tail=tail->next;
            } 

            p=p->next;
        }

        connect(temp.next);
    }
};


//迭代版本
class Solution {
public:
    void connect(TreeLinkNode *root) {

        if(root==NULL) return;
        TreeLinkNode* p;
      // 迭代版本
      while(root!=NULL){
         TreeLinkNode temp(0);
         TreeLinkNode* tail=&temp;
         p=root;
        while(p!=NULL){
             if(p->left==NULL&&p->right==NULL){
               p=p->next;
               continue;
             }
            else if(p->left!=NULL&&p->right!=NULL){
                 tail->next =p->left;
                 p->left->next=p->right;
                 tail=p->right;
            }
            else {
                tail->next = (p->left!=NULL)?p->left:p->right;
                tail=tail->next;
            } 

            p=p->next;
        }

         root=temp.next;
      }
    }
};
5.4.4 Binary Search Tree Iterator

维护一个结构从开头每次调用next,返回中序遍历下一个节点

思考:
用栈s保存每个根节点——一条路径
cur表示当前要考虑的根节点
cur 一直往左走,走过的节点入栈
最后一个出栈(无左子树),访问它,它就是下一个要考虑的节点, cur = s.top()
cur = cur->right;
注意缓存,如果调用两次hasNext不应该改变结果

个人思考: 实际上是中序遍历的迭代版本

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class BSTIterator {
public:
    BSTIterator(TreeNode *root) {
        while(root!=NULL){
            mystack.push(root);
            root=root->left;
        }
    }

    /** @return whether we have a next smallest number */
    bool hasNext() {
        return !mystack.empty();
    }

    /** @return the next smallest number */
    int next() {
        TreeNode* temp=mystack.top();
        mystack.pop();
        TreeNode* p;
        if(temp->right!=NULL){
            p=temp->right;
            while(p!=NULL){
                mystack.push(p);
                p=p->left;
            }
        }

        return temp->val;
    }
    private :
      stack<TreeNode* > mystack;
};

/**
 * Your BSTIterator will be called like this:
 * BSTIterator i = BSTIterator(root);
 * while (i.hasNext()) cout << i.next();
 */
5.4.5 Construct Binary Tree from Preorder and Inorder Traversal Leetcode 105

给定二叉树前、中序遍历,构造二叉树 (Leetcode 105)
分析:
前序遍历序列第一个是根节点x
从中序遍历序列中找到根节点x
中序遍历中x的左边序列对应等长的前序遍历序列
左子树
中序遍历中x的右边序列对应等长的前序遍历序列
右子树

class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        return helper(preorder,inorder,0,preorder.size()-1,0,inorder.size()-1);
    }
    TreeNode*  helper(vector<int>& preorder, vector<int>& inorder ,int pl,int ph ,int il,int ih){

        if(pl>ph) return NULL;
        TreeNode * root = new TreeNode(preorder[pl]);

        int i=il;
        for( ;i<=ih;i++){
            if(inorder[i]==preorder[pl])
              break;
        }

        int leftlen=i-il;
        int rightlen=ih-i;
        root->left = helper(preorder,inorder,pl+1,pl+leftlen,il,i-1);
        root->right =helper(preorder,inorder,pl+leftlen+1,ph,i+1,ih);

        return root;
    }
};
5.4.6 Construct Binary Tree from Inorder and Postorder Traversal leetcode 106

定二叉树后、中序遍历,构造二叉树
后序遍历序列最后一个是根节点x
从中序遍历序列中找到根节点x
中序遍历中x的左边序列对应等长的后序遍历序列
左子树
中序遍历中x的右边序列对应等长的后序遍历序列
右子树

class Solution {
public:
    TreeNode *buildTree(vector<int> &inorder, vector<int> &postorder) {
         if(inorder.size()==0)  return NULL;
         int N = inorder.size();
         TreeNode * ret= helper(inorder, postorder, 0,N-1 ,0,N-1)
         return ret;
    }

    TreeNode * helper(vector<int> &inorder, vector<int> &postorder, int instart ,int inend ,int postart,int poend) {
          if(instart==inend)  return new TreeNode(inorder[instart]);
          if(instart>inend)  return NULL;

           int last = postorder[poend];
           TreeNode * ret = new TreeNode(last);

           int mid=instart;
           for(int i=instart ;i<=inend ;i++)
              if(inorder[i]==last){
                   mid= i;
                   break;
             }
          ret->left= helper(inorder,postorder, instart,mid-1,postart,postart+(mid-1-instart));
          ret->right = helper(inorder,postorder, mid+1,inend,postart+(mid-1-instart)+1,poend-1);
          return ret;

     }
};
5.4.7 Convert Sorted Array to Binary Search Tree leetcode108

Given an array where elements are sorted in ascending order, convert it to a height balanced BST.

class Solution {
public:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
       return  helper(nums,0,nums.size()-1);
    }
    TreeNode* helper(vector<int>& nums, int start,int end){
        if(start>end) return NULL;
        int mid =start+(end-start)/2;
        TreeNode* root=new TreeNode(nums[mid]);
        root->left=helper(nums,start,mid-1);
        root->right =helper(nums,mid+1,end);
        return root;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值