二叉树算法题

1.二叉树深度

leetcode

int max(int a ,int b)
{
    return a > b ? a : b;
}

int maxDepth(struct TreeNode* root)
{
   if(root == NULL)
   return 0;
   int ret = max(maxDepth(root->left),maxDepth(root->right));
   return ret + 1;
}

解题思想:二叉树深度 == max(左子树深度,右子树深度)+1;


2.翻转二叉树

leetcode

class Solution {
public:
    TreeNode* invertTree(TreeNode* root)
    {
       if(root == NULL)
       return NULL;
       TreeNode* tmp = root->left;
       root->left = root->right;
       root->right = tmp;

       invertTree(root->left);
       invertTree(root->right);

       return root;
    }
};

解题思路:不断交换左右子树,直到为空


3.相同的树

leetcode

class Solution {
public:
    bool isSameTree(TreeNode* p, TreeNode* q) 
    {
       if(q == NULL && p == NULL)
       return true;
       if(q == NULL || p == NULL)
       return false;
       if(q->val != p->val)
       return false;

       return isSameTree(q->left,p->left) && isSameTree(q->right,p->right);
    }
};

解题思路:问题拆分
两棵树不同的情况
1.结构不同
即p == NULL || q == NULL;
2.结点值不同
即p->val != q->val;
然后递归子树即可;


4.对称二叉树

leetcode

class Solution {
public:
    bool child(TreeNode* q,TreeNode* p)
    {
        if(q == nullptr && p == nullptr)
        return true;
        if(q == nullptr || p == nullptr)
        return false;
        if(q->val != p->val)
        return false;
        return child(q->right,p->left) && child(q->left,p->right);
    }
    bool isSymmetric(TreeNode* root) 
    {
       if(root == nullptr)
       return true;
       return child(root->left,root->right);
    }
};

解题思路
化为子问题解决,最后递归求出左右子树是否对称;

5、二叉树的遍历

遍历

6.二叉树的层序遍历

leetcode

先不考虑按层输出,写一个二叉树的层序遍历;

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) 
    {
        vector<vector<int>> vv;
       queue<TreeNode*> q;
       if(root)
       q.push(root);
       while(!q.empty())
       {
           TreeNode* front = q.front();
           q.pop();
           cout << front->val;
           if(front->left)
           q.push(front->left);
           if(front->right)
           q.push(front->right);

       } 
       return vv;
    }
};

在此基础上,加入分层输出模块即可

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) 
    {
        vector<vector<int>> vv;
       queue<TreeNode*> q;
       if(root)
       q.push(root);
       while(!q.empty())
       {
           int queue_size = q.size();
           vector<int> v;
           for(int i = 0; i < queue_size ;++i)
           {
              TreeNode* front = q.front();
              q.pop();
              v.push_back(front->val);
              if(front->left)
              q.push(front->left);
              if(front->right)
              q.push(front->right);
           }
           vv.push_back(v);
       } 
       return vv;  
    }
};

解题思路
可以用一个循环控制每层输出的节点数量,并插入数组,而循环的控制变量如何选取?

观察发现,队列的元素个数是不断增加的,上一次循环增加的节点数,恰好是第二次循环需要输出的元素个数,再将元素插入数组即可;

7.二叉树的层序遍历II

leetcode

解题思路:在前一题的基础上加上逆置即可,使用库函数reverse;

8.二叉树的最近公共祖

leetcode

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root == NULL)return NULL;        
        if(root == p||root == q)return root;
        TreeNode* left = lowestCommonAncestor(root->left, p, q);
        TreeNode* right = lowestCommonAncestor(root->right, p, q);
        if(left && right)return root;
        return left ? left : right; // 只有一个非空则返回该指针,两个都为空则返回空指针
    }
};

解题思路

1.如果俩个节点分别处于左右子树,则当前根节点就是最近公共祖先

2.如果当处于左子树,则返回递归到左子树的值,右子树亦然;

8.2搜索树的最近祖先

leetcode

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root == NULL)return NULL;
        if(p->val > root->val && q->val > root->val) 
            return lowestCommonAncestor(root->right, p, q);
        else if(p->val < root->val && q->val < root->val) 
            return lowestCommonAncestor(root->left, p, q);
        else return root;
    }
};

解题思路:搜索树左子树都比自己小,右子树都比自己大;

利用该性质,可以分三类:

1.一个值比自己大,一个比自己小,则该节点就是最近祖先;

2.都比自己小,递归到左子树,比自己大,递归到右子树;

9.二叉树与双向链表

leetcode

class Solution {
private:
	Node* head;
	Node* pre;
	//cur中序遍历
	void inorder(Node* cur) {
		if (cur == nullptr)return;
		inorder(cur->left);
		//转换
		//当pre不为空时 需要将cur->left = pre, pre->right = cur , 再将pre指向cur
		if (pre != nullptr) 
        {
			pre->right = cur;
			cur->left = pre;
            pre = cur;
		}
		else 
        {
		//当pre为nullptr 时 表示cur->val 为最小即为head头结点 只需要令head = cur,再将pre指向cur
			head = cur;
            pre = cur;
		}
		inorder(cur->right);
	}
public:
	Node* treeToDoublyList(Node* root) {
		if (root == nullptr)return root;
		inorder(root);
		//处理头尾
		head->left = pre;
		pre->right = head;
		return head;
	}
};

解题思路

将搜索树转化为排序的双向链表

  1. 通过排序可以想到搜索树的特性,即中序为有序;

  2. 双向则为可以想到左右指向改为链表的前后指针;

综上:核心代码为

cur->left = pre;//
if(pre)
    pre->right = cur;
pre = cur;

10.重建二叉树

leetcode

class Solution {
public:
     TreeNode* _buildTree(vector<int>& preorder, vector<int>& inorder ,int& prei ,int inbegin , int inend)
     {
        if(inbegin > inend)//传入空节点
        return NULL;

        TreeNode* root = new TreeNode(preorder[prei]);//根节点处于前序第一个位置
        int rooti = inbegin;
         //寻找中序根节点的位置
        while(rooti < inend)
        {
            if(inorder[rooti] == preorder[prei])
            break;
            else
            ++rooti;
        }
        if(inbegin <= rooti-1)//递归重建左树
        root->left = _buildTree(preorder,inorder,++prei,inbegin,rooti-1);
        else
        root->left = NULL;
        if(inend >= rooti+1)//递归重建右树
        root->right = _buildTree(preorder,inorder,++prei,rooti+1,inend);
        else
        root->right = NULL;
      return root;
     }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) 
    {
       int prei = 0;
       int inbegin = 0 , inend = inorder.size() - 1;

       return _buildTree(preorder,inorder,prei,inbegin,inend);
    }
};

解题思路

  1. 二叉树的中序和前序可以重建一颗二叉树;
  2. 前序可以确定根节点的位置;
  3. 中序找到根节点后可以分为左右子树的递归重建;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值