翻转二叉树以匹配先序遍历

语言: C++

题目描述 :

给定一个有 N 个节点的二叉树,每个节点都有一个不同于其他节点且处于 {1, ..., N} 中的值。

通过交换节点的左子节点和右子节点,可以翻转该二叉树中的节点。

考虑从根节点开始的先序遍历报告的 N 值序列。将这一 N 值序列称为树的行程。

(回想一下,节点的先序遍历意味着我们报告当前节点的值,然后先序遍历左子节点,再先序遍历右子节点。)

我们的目标是翻转最少的树中节点,以便树的行程与给定的行程 voyage 相匹配。 

如果可以,则返回翻转的所有节点的值的列表。你可以按任何顺序返回答案。

如果不能,则返回列表 [-1]。

示例 1:

输入:root = [1,2], voyage = [2,1]
输出:[-1]


示例 2:

输入:root = [1,2,3], voyage = [1,3,2]
输出:[1]


示例 3:

输入:root = [1,2,3], voyage = [1,2,3]
输出:[ ]

提示:

1 <= N <= 100

来源:力扣(LeetCode)
OJ链接:https://leetcode-cn.com/problems/flip-binary-tree-to-match-preorder-traversal

思路分析 :

关键点: 范围[1 - N] , 无重复节点, 前序遍历 

思路比较简单, 既然没有重复节点, 就不用考虑判断过的节点是否需要重新判断一遍的问题. 例如下面的二叉树

在匹配 [1, 2, 3, 4, 5, 6, 7, 2, 3, 6, 5, 4, 7 ] 这个序列时, 只需要把根节点的左右孩子(蓝色圈)交换就可以了, 但在前序遍历二叉树的过程中, 遍历到2时并无法判断出是否要交换, 所以一直要遍历到6(红色圈), 此时发现与序列不匹配, 之前所有遍历过的祖先节点都有可能是满足条件的交换节点.   ̄へ ̄  说了这么多, 本题不需要考虑这种情况

所以只需要在前序遍历二叉树的同时也顺序遍历给出的序列, 依次比较遍历到的节点与序列是否相等, 记录遍历的当前节点

的父节点, 如果当前节点与序列不相等, 则交换记录的父节点的两个左右孩子. 再从父节点开始往下遍历. 

注意:

1.在交换左右孩子时, 只要有一个孩子为空, 肯定不匹配

2. 当交换后的还没相等, 肯定不匹配

 

 

class Solution {
    bool Swap(TreeNode*& root) {
        if (!root->left || !root->right) {//在交换左右孩子时, 只要有一个孩子为空, 肯定不匹配
            return false;
        }
        TreeNode* tmp = root->left;
        root->left = root->right;
        root->right = tmp;
        return true;
    }
public:
    vector<int> flipMatchVoyage(TreeNode* root, vector<int>& voyage) {
        vector<int> res;
        stack<TreeNode*> s;
        bool flag = false;//标记是否出现不匹配的节点,如出现则置true,交换后相等则再置为false
        TreeNode* f = root;
        if (root->val != voyage[0]) {
            res.push_back(-1);
            return res;
        }
        int size = voyage.size();

        for (int i = 1; root && i < size;) {
            f = root;
            if (root->right) s.push(root->right);
            if (root->left) s.push(root->left);
            if (s.empty()) {
                root = nullptr;
            }
            else {
                root = s.top();
                s.pop();
                //判断
                if (root->val != voyage[i]) {
                    if (flag) {//交换后的还没相等, 肯定不匹配
                        res.clear();
                        res.push_back(-1);
                        return res;
                    }
                    flag = true;
                    if (Swap(f)) {
                        if (!s.empty())s.pop();
                        root = f;
                    }
                    else {
                        res.clear();
                        res.push_back(-1);
                        return res;
                    }
                }
                else {
                    if (flag) {
                        flag = false;
                        res.push_back(f->val);
                    }
                    ++i;
                }
            }
        }
        return res;
    }
};

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值