算法|Day18 二叉树7

LeetCode 530- 二叉搜索树的最小绝对差

题目链接:力扣

题目描述:给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值

差值是一个正数,其数值等于两值之差的绝对值。

解题思路

思路一:

  • 中序遍历,然后用数组记录遍历结果,再比对最小值。

思路二:

  • 由于二叉搜索树的性质,我们可以使用双指针法。
  • 二叉搜索树在中序遍历时,遍历顺序是从大到小,所以最小差值肯定是遍历时两个相邻节点之间产生。所以可以用双指针法,一个指针记录pre一个记录cur,然后来遍历整棵树,记录下最小差值即可。
class Solution {
private:
int result = INT_MAX;
TreeNode* pre = NULL;
void traversal(TreeNode* cur) {
    if (cur == NULL) return;
    traversal(cur->left);   // 左
    if (pre != NULL){       // 中
        result = min(result, cur->val - pre->val);
    }
    pre = cur; // 记录前一个
    traversal(cur->right);  // 右
}
public:
    int getMinimumDifference(TreeNode* root) {
        traversal(root);
        return result;
    }
};

总结:

二叉搜索树,优化方法大都是利用其中序遍历有序的性质来的,遇到这种题要往这方面想。

LeetCode 501- 二叉搜索树中的众数

题目链接:力扣

题目描述:给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。

如果树中有不止一个众数,可以按 任意顺序 返回。

假定 BST 满足如下定义:

结点左子树中所含节点的值 小于等于 当前节点的值

结点右子树中所含节点的值 大于等于 当前节点的值

左子树和右子树都是二叉搜索树

解题思路

  • 又是二叉搜索树,可以利用二叉搜索树的性质,使用双指针。
  • 在中序遍历时,遍历结果是从大到小的,所以两个数相等的情况只可能是遍历相邻节点时出现。所以右可以使用双指针法。就能判断众数。
  • 使用一个Count来记录当前的数出现次数,maxCount来记录当前众数的出现次数。当Count<maxCount时Count++(并且还pre->val == cur->val),Count==maxCount时将当前数加入至结果集中;当Count>maxCount时将结果集清空,并更新maxCount=Count,然后将当前的数加入到结果集中去。
class Solution {
private:
    int maxCount = 0; // 最大频率
    int count = 0; // 统计频率
    TreeNode* pre = NULL;
    vector<int> result;
    void searchBST(TreeNode* cur) {
        if (cur == NULL) return ;
        searchBST(cur->left);       // 左
                                    // 中
        if (pre == NULL) { // 第一个节点,出现次数就是1
            count = 1;
        } else if (pre->val == cur->val) { // 与前一个节点数值相同
            count++;
        } else { // 与前一个节点数值不同,说明第一次出现设置为1
            count = 1;
        }
        pre = cur; // 更新上一个节点
        if (count == maxCount) { // 如果和最大值相同,放进result中
            result.push_back(cur->val);
        }
        if (count > maxCount) { // 如果计数大于最大值频率
            maxCount = count;   // 更新最大频率
            result.clear();     // 很关键的一步,不要忘记清空result,之前result里的元素都失效了
            result.push_back(cur->val);
        }
        searchBST(cur->right);      // 右
        return ;
    }

public:
    vector<int> findMode(TreeNode* root) {
        result.clear();

        searchBST(root);
        return result;
    }
};

总结:

  • 自己写的时候不知道只有俩个节点的时候怎么处理,题解中有处理就是将pre==NULL作为第一个节点时的特殊处理,开始没想到。

LeetCode 236- 二叉树的最近公共祖先

题目链接:力扣

题目描述:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先.

解题思路:

思路一(两个栈处理深度优先):

  • 我们可以记录二叉树的遍历路径,深度优先遍历,当我们往下遍历时会将前面遍历过的节点记录下来,当遇到目标节点时就返回。栈中保存的就是我们遍历的路径,有相同的祖先的两个节点它们的遍历路径在栈中肯定有相同部分,我们可以依据这个来找到公共祖先(最开始也想到了这个,就是不知道该怎么回溯)。

class Solution {
public:
	//函数就是找从根节点到指定节点的路径
    bool getPath(TreeNode* root, TreeNode* target, stack<TreeNode*>& path) {
    if (root == nullptr) {
        return false;  // 空节点返回false
    }
    path.push(root);  // 将当前节点入栈

    if (root == target) {  // 当前节点是目标节点
        return true;
    }

    if (getPath(root->left, target, path)) {  // 在左子树中找目标节点,找到直接返回
        return true;
    }

    if (getPath(root->right, target, path)) {  // 在右子树中找目标节点,找到直接返回给上一层
        return true;
    }

    path.pop();  // 当左右都没找到,回溯时将当前节点出栈,再去试别的路
    return false;
}

// 主函数:找到两个节点的最近公共祖先
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    stack<TreeNode*> path1, path2;
    getPath(root, p, path1);
    getPath(root, q, path2);
     if (path1.empty() || path2.empty()) {
        return nullptr;
    }
    while(path1.size()>path2.size()){
        path1.pop();
    }
    while(path2.size()>path1.size()){
        path2.pop();
    }
    TreeNode* result = nullptr;
    while (!path1.empty() && !path2.empty()) {
        if (path1.top() == path2.top()) {
            result = path1.top();
            break;
        }
        path1.pop();
        path2.pop();
    }

    return result;
}
};

思路二(后序遍历处理):

  • 后序遍历的顺序是左右中,我们可以用后序遍历来看两个节点是否有公共祖先
  • 首先确定终止条件,当我们遇到空或者是找到了p、q都要返回直接返回root。
  • 其次是单层递归逻辑,先左后右,当left和right都找到了,也就是都不为空,我们就可以返回当前的root作为答案,如果左边找到了,就把左边往上返回,右边找到了就把右边往上返回,左右都没有找到就返回NULL。

看看流程图

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

        if (left == NULL && right != NULL) return right;
        else if (left != NULL && right == NULL) return left;
        else  { //  (left == NULL && right == NULL)
            return NULL;
        }

    }
};

总结

  • 这题就是先找节点,找到之后一层一层的返回,当两边的返回值都不为空,那就是公共祖先了。用栈的解法的思路最后也挺像的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值