leetcode--99. 恢复二叉搜索树(dfs)

记录
0:10 2024-2-2

https://leetcode.cn/problems/recover-binary-search-tree

==做了好久没做出来看的题解做的。
分析原因:对dfs还是不够熟悉,特别是涉及到前/中/后序遍历的性质上


因为对二叉搜索树中序遍历得到的结果必然是非递减的,所以找到不合格的地方就行了。
如果是相邻两个数交换,如\(a_i > a_{i+1}\) 那么 nums[i], nums[j+1]就是需要交换的数
如果是间隔的两个数交换,会导致\(a_i > a_{i+1} 和 a_j > a_{j+1} (j - i > 1)\) 那么 nums[i], nums[j+1]就是需要交换的数


1.简单做法就是dfs遍历找到不对的数进行交换
2.不需要显式中序遍历找到不对的数,需要利用栈来迭代,并且每次记住上次的值用于比较
3.Morris 中序遍历


简单做法

点击查看代码
    //找到不同顺序数
    std::pair<int, int> findDiffOrder(vector<int> nums) {
        int err1 = -1, err2 = -1;
        for(int i = 0; i < nums.size() - 1; i++) {
            if(nums[i] > nums[i + 1]) {
                if(err1 == -1) err1 = i;
                else err2 = i + 1;
            }
        }
        if(err2 == -1) err2 = err1 + 1;
        return make_pair(nums[err1], nums[err2]);
    }

    void inOrder(TreeNode* root, vector<int>& nums) {
        if(root == nullptr) return;
        inOrder(root->left, nums);
        nums.push_back(root->val);
        inOrder(root->right, nums);
    }

    void solve(TreeNode* root, std::pair<int, int> diff) {
        if(root == nullptr) return;
        if(root->val == diff.first) root->val = diff.second;
        else if(root->val == diff.second) root->val = diff.first;
        solve(root->left, diff);
        solve(root->right, diff);
    }

    void recoverTree(TreeNode* root) {
        vector<int> nums;
        inOrder(root, nums);
        std::pair<int, int> diff = findDiffOrder(nums);
        solve(root, diff);
    }

这里是迭代的方式,把一个节点左子树的最右节点的右连接到root上,其实是不用栈的中序遍历方法


中序遍历(递归实现) ===>

中序遍历(迭代实现 利用栈 第二次遇见节点的时候利用节点数据) 可以参考数据结构学习第十三天里的前/中/后序遍历输出部分 ===>

Morris中序遍历(迭代实现 不利用栈 也是第二次遇见节点的时候利用节点数据 这里是利用predecessor的右孩子不为空表示第二次遇到节点)


Morris 中序遍历

点击查看代码
void inOrder() {
        TreeNode *x = nullptr, *y = nullptr, *pred = nullptr, *predecessor = nullptr;

        while (root != nullptr) {
            if (root->left != nullptr) {
                // predecessor 节点就是当前 root 节点向左走一步,然后一直向右走至无法走为止
                predecessor = root->left;
                while (predecessor->right != nullptr && predecessor->right != root) {
                    predecessor = predecessor->right;
                }
                
                // 让 predecessor 的右指针指向 root,继续遍历左子树
                if (predecessor->right == nullptr) {
                    predecessor->right = root;
                    root = root->left;
                }
                // 说明左子树已经访问完了,我们需要断开链接
                else {
                    if (pred != nullptr && root->val < pred->val) {
                        y = root;
                        if (x == nullptr) {
                            x = pred;
                        }
                    }
                    pred = root;

                    predecessor->right = nullptr;
                    root = root->right;
                }
            }
            // 如果没有左孩子,则直接访问右孩子
            else {
                pred = root;
                root = root->right;
            }
        }
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/recover-binary-search-tree/solutions/365385/hui-fu-er-cha-sou-suo-shu-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处

posted @ 2024-02-02 01:31  57one  阅读(2)  评论(0编辑  收藏  举报