代码随想录算法训练营第21天|二叉树part07|530. 二叉搜索树的最小绝对差、501.二叉搜索树中的众数、236. 二叉树的最近公共祖先

代码随想录算法训练营第21天|二叉树part07|530. 二叉搜索树的最小绝对差、236. 二叉树的最近公共祖先

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

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

自己做

思路:

因为是二叉搜索树,所以我想到使用中序遍历

想着一次递归就实现求最小绝对差,但是发现根结点的前驱节点无法记录,需要使用全局的前驱指针,在递归函数里面传递pre不行

因此失败

代码:

python

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def __init__(self):
        self.minDiff = 10e4
    def getMinimumDifference(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        # 利用二叉搜索树的特性,最小差值一定出现在相邻的两个结点之间
        # 中序遍历
        pre = None
        self.helper(pre, root)
        return self.minDiff
    
    def helper(self, pre, root):
        if root == None:
            return 
        self.helper(root, root.left)
        
        if pre:
            if abs(pre.val - root.val) < self.minDiff:
                self.minDiff = abs(pre.val - root.val)
        # 根结点的前驱节点如何解决,根结点的后继节点如何解决
        self.helper(pre, root.right)

代码随想录

思路:

递归 + 中序 + 结合数组

代码:

python

class Solution:
    def __init__(self):
        self.vec = []

    def traversal(self, root):
        if root is None:
            return
        self.traversal(root.left)
        self.vec.append(root.val)  # 将二叉搜索树转换为有序数组
        self.traversal(root.right)

    def getMinimumDifference(self, root):
        self.vec = []
        self.traversal(root)
        if len(self.vec) < 2:
            return 0
        result = float('inf')
        for i in range(1, len(self.vec)):
            # 统计有序数组的最小差值
            result = min(result, self.vec[i] - self.vec[i - 1])
        return result

或者采用一个全局的pre指针

class Solution:
    def __init__(self):
        self.result = float('inf')
        self.pre = None

    def traversal(self, cur):
        if cur is None:
            return
        self.traversal(cur.left)  # 左
        if self.pre is not None:  # 中
            self.result = min(self.result, cur.val - self.pre.val)
        self.pre = cur  # 记录前一个
        self.traversal(cur.right)  # 右

    def getMinimumDifference(self, root):
        self.traversal(root)
        return self.result

501.二叉搜索树中的众数

501.二叉搜索树中的众数

自己做

自己做没有做出来,原因是把计数和更新结果数组放到一起了,比较混乱,而代码随想录则分开来处理,思路清晰,不易错!

思路:

代码:

python


代码随想录

思路:

  1. 如果不是二叉搜索树

如果不是二叉搜索树,最直观的方法一定是把这个树都遍历了,用map统计频率,把频率排个序,最后取前面高频的元素的集合。

  1. 既然是搜索树,它中序遍历就是有序的。

关键是在有序数组上的话,好搞,在树上怎么搞呢?

弄一个指针指向前一个节点,这样每次cur(当前节点)才能和pre(前一个节点)作比较。

而且初始化的时候pre = NULL,这样当pre为NULL时候,我们就知道这是比较的第一个元素。

如果 频率count 等于 maxCount(最大频率),当然要把这个元素加入到结果集中(以下代码为result数组)

如果频率count 大于 maxCount的时候,不仅要更新maxCount,而且要清空结果集(以下代码为result数组)

下面的代码分两步处理:一步处理count, 一步处理结果数组

代码:

python

class Solution:
    def __init__(self):
        self.maxCount = 0  # 最大频率
        self.count = 0  # 统计频率
        self.pre = None
        self.result = []

    def searchBST(self, cur):
        if cur is None:
            return

        self.searchBST(cur.left)  # 左
        # 中
        if self.pre is None:  # 第一个节点
            self.count = 1
        elif self.pre.val == cur.val:  # 与前一个节点数值相同
            self.count += 1
        else:  # 与前一个节点数值不同
            self.count = 1
        self.pre = cur  # 更新上一个节点

        if self.count == self.maxCount:  # 如果与最大值频率相同,放进result中
            self.result.append(cur.val)

        if self.count > self.maxCount:  # 如果计数大于最大值频率
            self.maxCount = self.count  # 更新最大频率
            self.result = [cur.val]  # 很关键的一步,不要忘记清空result,之前result里的元素都失效了

        self.searchBST(cur.right)  # 右
        return

    def findMode(self, root):
        self.count = 0
        self.maxCount = 0
        self.pre = None  # 记录前一个节点
        self.result = []

        self.searchBST(root)
        return self.result

236. 二叉树的最近公共祖先

236. 二叉树的最近公共祖先

自己做

思路:

代码:

python

按照代码随想录的思路自己编的

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def lowestCommonAncestor(self, root, p, q):
        """
        :type root: TreeNode
        :type p: TreeNode
        :type q: TreeNode
        :rtype: TreeNode
        """
        if root == q or root == p or root == None:
            return root
        

        left = self.lowestCommonAncestor(root.left, p, q)
        right = self.lowestCommonAncestor(root.right, p , q)

        if left and right:
            return root
        if not left and right:
            return right
        if left and not right:
            return left
        if not left and not right:
            return None

        
        

代码随想录

思路:

自底向上查找

回溯啊,二叉树回溯的过程就是从低到上。

后序遍历(左右中)就是天然的回溯过程,

情况一:

首先最容易想到的一个情况:如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。

在这里插入图片描述
情况二:就是节点本身p(q),它拥有一个子孙节点q§。

代码实现过程都是一样的,也可以说,实现情况一的逻辑,顺便包含了情况二
在这里插入图片描述
递归三部曲:

  1. 确定递归函数返回值以及参数

    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)

  2. 确定终止条件

遇到空的话,因为树都是空了,所以返回空。

如果 root == q,或者 root == p,说明找到 q p ,则将其返回,这个返回值

处理了情况二

if (root == q || root == p || root == NULL) return root;
  1. 确定单层递归逻辑

本题函数有返回值,该怎么写呢?

搜索一条边的写法:

if (递归函数(root->left)) return ;

if (递归函数(root->right)) return ;

搜索整个树写法:

left = 递归函数(root->left);  // 左
right = 递归函数(root->right); // 右
left与right的逻辑处理;         // 中 

在递归函数有返回值的情况下:如果要搜索一条边,递归函数返回值不为空的时候,立刻返回,如果搜索整个树,直接用一个变量left、right接住返回值,这个left、right后序还有逻辑处理的需要,也就是后序遍历中处理中间节点的逻辑(也是回溯)。

本题需要遍历整棵树

因为在如下代码的后序遍历中,如果想利用left和right做逻辑处理, 不能立刻返回,而是要等left与right逻辑处理完之后才能返回。

如果left 和 right都不为空,说明此时root就是最近公共节点。这个比较好理解

如果left为空,right不为空,就返回right,说明目标节点是通过right返回的,反之依然。

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

代码:

c++

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;
        }

    }
};

python

class Solution:
    def lowestCommonAncestor(self, root, p, q):
        if root == q or root == p or root is None:
            return root

        left = self.lowestCommonAncestor(root.left, p, q)
        right = self.lowestCommonAncestor(root.right, p, q)

        if left is not None and right is not None:
            return root

        if left is None and right is not None:
            return right
        elif left is not None and right is None:
            return left
        else: 
            return None
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值