Leetcode-DFS+BST

本文介绍如何解决二叉搜索树中元素错误交换的问题,并验证一棵二叉树是否为有效的二叉搜索树。通过中序遍历的方法,不使用额外数组,在常数空间复杂度下实现解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem

Decription For Problem1(Recover Binary Search Tree)

Two elements of a binary search tree (BST) are swapped by mistake.

Recover the tree without changing its structure.

Note:
A solution using O(n) space is pretty straight forward. Could you devise a constant space solution?

具体详见Leetcode

Decription For Problem2(Validate Binary Search Tree)

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.
具体详见Leetcode

Analysis

初步想法

先看问题一,因为有两个节点的位置被交换了,导致给出的二叉搜索树不符合二叉搜索树的规定,就是节点左子树的值比它小,右子树的值比它大。那么一开始的想法就是,因为二叉搜索树的有序性能够让我们很轻易地就能看出来哪两个节点之间的位置发生了互换。然后,二叉搜索树最直接能让我们看出来顺序的就是中序遍历。所以,初步的想法是开两个数组,一个存储中序遍历出来的值,另一个存储这些值对应的节点的指针,然后方便到时候直接更改。
但是,我们注意到题目的要求:

A solution using O(n) space is pretty straight forward. Could you devise a constant space solution?

如果开两个数组的话空间复杂度势必是 O(n) ,如果想要 O(1) 的空间复杂度的话就不能用数组,只能用一些变量来实现同样的功能。

可能的改进

所以,我们现在的大方向是利用DFS中序遍历整个二叉搜索树,然后利用一两个变量实现找到不符合条件的节点,然后最后进行交换。
最简单的一种情况是,被交换的两个错误节点刚好是父子关系,那么直接交换即可。但是,如果不是父子关系的话,那么他们之间的距离就会比较遥远,相对比较麻烦。
通过观察,我们可以发现,如果两个节点相距比较远的话,它们和第一种简单的情况的共性就是它们在中序遍历出来的有序数列里会出现一些不符合要求的数对,这些数对前面的数比较大,后面的数比较小。有父子关系的节点它们的这种数对只会出现一次,而没有父子关系的会出现一次以上。
然后通过这样的发现,我们就可以做到正确的判断。首先,我们先把中序遍历的上一个点的值和它的指针(也可以只存指针)存起来,然后访问到当前节点的时候判断前面的值是否比自己大,如果是,是不是第一对,如果不是就直接可以把这个节点存起来,因为它已经是第二次出现了,而且肯定是较小的那个节点,所以直接存起来,如果不是,也存储起来,以后再交换。
然后,看到问题二,我们发现虽然问题不一样,但是核心的方法还是一样的,都是借助DFS实现中序遍历,通过有序性来判断是否合法。

Code

Recover Binary Search Tree

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    void recoverTree(TreeNode* root) {
        DFS(root);
        if (e3 == NULL) {
            int temp = e1->val;
            e1->val = e2->val;
            e2->val = temp;
        } else {
           int temp = e1->val;
            e1->val = e3->val;
            e3->val = temp ;
        }
    }
    void DFS(TreeNode* node) {
        if (node == NULL) return;

        DFS(node->left);
        if (prev == -1) {
            prev = node->val;
            pre = node;
        } else {
            if (prev > node->val) {
                if (e1 == NULL) {

                    e1 = pre;
                    e2 = node;

                } else {
                    e3 = node;
                }

            }
            pre = node;
            prev = node->val;
        }
        cout << prev << endl;
        DFS(node->right);
    }
private:
    TreeNode* pre;
    TreeNode* e1;
    TreeNode* e2;
    TreeNode* e3;
    int prev = -1;
};

Validate Binary Search Tree

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool isValidBST(TreeNode* root) {
        flag = true;
        DFS(root);
        return flag;
    }
    void DFS(TreeNode* node) {
        if (node == NULL) return;

        DFS(node->left);
        if (prev == -1) {
            prev = node->val;
        } else {
            if (prev >= node->val) {
                flag =  false;

            }

            prev = node->val;
        }

        DFS(node->right);
    }
private:
    int prev = -1;
    bool flag;
};

Complexity

因为我们遍历了所有的节点,所以时间复杂度和节点数有关。空间复杂度要求是常数级的所以也可以确定了。
时间复杂度: O(n)
空间复杂度: O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值