二叉树(思路)

二叉树(思路)

二叉树做题思维模型!!

二叉树解题的思维模式分两类:

1、是否可以通过遍历一遍二叉树得到答案?如果可以,用一个 traverse 函数配合外部变量来实现,这叫「遍历」的思维模式。

2、是否可以定义一个递归函数,通过子问题(子树)的答案推导出原问题的答案?如果可以,写出这个递归函数的定义,并充分利用这个函数的返回值,这叫「分解问题」的思维模式。

无论使用哪种思维模式,你都需要思考:

如果单独抽出一个二叉树节点,它需要做什么事情?需要在什么时候(前/中/后序位置)做?其他的节点不用你操心,递归函数会帮你在所有节点上执行相同的操作。

226. 翻转二叉树

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

image-20220401123444524

思路

是否可以通过遍历实现?

可以。写一个 traverse 函数遍历每个节点,让每个节点的左右子节点颠倒过来就行了。

单独抽出一个节点,需要让它做什么?让它把自己的左右子节点交换一下。

需要在什么时候做?好像前中后序位置都可以。

遍历实现:

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if (root == NULL) return root;
        swap(root->left, root->right);  // 中
        invertTree(root->left);         // 左
        invertTree(root->right);        // 右
        return root;
    }
};

递归分解实现

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

        root->left = right;
        root->right = left;

        return root;
    }
};

116. 填充每个节点的下一个右侧节点指针

给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。image-20220401125948034

思路

你可以把二叉树的相邻节点抽象成一个「三叉树节点」,这样二叉树就变成了一棵「三叉树」,然后你去遍历这棵三叉树,把每个「三叉树节点」中的两个节点连接就行

这个思路确实难想,但是画图的时候,连接相邻结点其实就两种情况

  1. 连接父节点相同的两个子节点
  2. 连接父节点不同的两个节点

然后递归实现就行

image-20220401130846962

代码实现

class Solution {
public:
    Node* connect(Node* root) {
        if(!root) return root;
        traverse(root->left,root->right);
        return root;
    }
    void traverse(Node* l,Node* r){
        if(!l || !r) return;
        //前序遍历,将传入的两个节点连接起来
        l->next = r;
        //连接父节点相同的两个节点
        traverse(l->left,l->right);
        traverse(r->left,r->right);

        //连接相邻但是不同父节点的两个子节点
        traverse(l->right,r->left);
    }
};

114. 二叉树展开为链表

给你二叉树的根结点 root ,请你将它展开为一个单链表:

  • 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null
  • 展开后的单链表应该与二叉树 先序遍历 顺序相同。

思路:

很简单,以下流程:

1、将 root 的左子树和右子树拉平。

2、将 root 的右子树接到左子树下方,然后将整个左子树作为右子树。

image-20220401172116810

class Solution {
public:
    void flatten(TreeNode* root) {
        if(!root) return;
        //先递归拉平左右子树
        flatten(root->left);
        flatten(root->right);

        //后序遍历位置 对当前结点的处理
        //1、左右子树已经被拉成一条链表
        TreeNode* l = root->left;
        TreeNode* r = root->right;

        //2、处理当前结点的作用子树,将左子树作为右子树,右子树放在左子树最右
        root->left = NULL;
        root->right = l;

        //3、将原来的右子树放在左子树的最右端
        TreeNode* p = root;
        while(p->right){
            p = p->right;
        }
        p->right = r;

    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值