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

碎碎念:
参考:代码随想录

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

题目链接

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

思想

直白想法:
先中序遍历,得到有序的序列,然后再求最小绝对差。
这样的操作多开辟了一个数组,其实可以优化,使用双指针来求最小绝对差。
双指针优化:
定义一个pre指向当前遍历之前的节点。
定义一个全局变量result,出事为maxint,记录相邻节点差值的最小值。
递归三部曲:

  1. 参数和返回值
  2. 终止条件:cur遍历到NULL。
  3. 单层递归:左:向左递归。
    中:当pre!=NULL,计算pre和cur指向节点值的差值,更新最小的result。更新pre和cur。
    右:向右递归。

题解

class Solution {
public:
    int result = INT_MAX;
    TreeNode* pre = NULL;
    void traversal(TreeNode* cur) {
        if (cur ==  NULL) return;
        traversal(cur->left); // 输入的是cur->left  暗含回溯
        if (pre != NULL) {
            result = min(result, cur->val - pre->val);
        }
        pre = cur;
        traversal(cur->right);

    }
    int getMinimumDifference(TreeNode* root) {
        traversal(root);
        return result;
    }
};
class Solution:
    def __init__(self):
        self.result = float('inf')
        self.pre = None


    def traversal(self, cur):
        if not cur:
            return
        self.traversal(cur.left)
        if self.pre:
            self.result = min(self.result, cur.val - self.pre.val)
        self.pre = cur    
        self.traversal(cur.right)
    
    def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
        self.traversal(root)
        return self.result

反思

注意本题也是暗含回溯的。

501.二叉搜索树中的众数

题目链接

501.二叉搜索树中的众数

思想

普通二叉树的解法: 要把符合题意的解都放到数组中。用map来统计元素出现的频率。然后map转为vector进行排序。再求众数。
如何利用二叉搜索树的特性来求众数。
遇到二叉搜索树时一定是中序遍历。因为中序遍历得到的序列是有序的。
问题:需要遍历两遍二叉树?第一遍得出出现的最大的频率,第二遍再得出出现频率等于最大频率的数(也就是众数)
双指针思路: pre指向前一个元素,取一个count,统计单个元素的频率,cur和pre相等的时候,count++,如果count和maxcount相等的时候,就把数值放入结果数组。
定义一个pre指针,一个count,一个maxcount,一个结果集。
递归三部曲:

  1. 参数和返回值:结果记在结果集里面,所以不需要返回值。
  2. 终止条件:遇到空的话就返回。
  3. 单层递归逻辑:中序遍历。
    左:向左递归遍历。
    中:统计元素出现的频率。注意处理pre是NULL的情况。
    如果pre指向的数值和cur的数值相等,count++,如果pre数值和cur数值不相等,count=1。pre要跟在cur的后面:pre = cur。
    如果count==maxcount,把当前的数值放入结果集中。
    如果count>maxcount,更新maxcount,清空result数组,把目前count对应的值放入结果集。

    👆避免两次遍历二叉树。
    右:向右递归遍历。

题解

class Solution {
public:
    int count = 0;
    int maxCount = 0;
    TreeNode* pre = NULL;
    vector<int> result; // 在遍历的过程中更新maxCount和result,从而避免需要遍历两次二叉树

    void searchBST(TreeNode* cur) {
        if (cur == NULL)  return;
        searchBST(cur->left);
        if (pre == NULL) {
            count = 1;
        } else if(pre->val == cur->val) {
            count++;
        } else {
            count = 1;
        }
        pre = cur;
        if (count == maxCount) {
            result.push_back(cur->val);
        }
        if (count > maxCount) {
            maxCount = count;
            result.clear();
            result.push_back(cur->val);
        }
        searchBST(cur->right);
        return;
    }
    vector<int> findMode(TreeNode* root) {
        result.clear();
        searchBST(root);
        return result;
    }
};
class Solution:
    def __init__(self):
        self.maxCount = 0
        self.count = 0
        self.pre = None
        self.result = []

    def searchBST(self, cur):
        if not cur:
            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:
            self.result.append(cur.val)
        
        if self.count > self.maxCount:
            self.maxCount = self.count
            self.result = [cur.val]
        
        self.searchBST(cur.right)
        return

    def findMode(self, root: Optional[TreeNode]) -> List[int]:
        self.result = []

        self.searchBST(root)
        return self.result

反思

注意对maxcount的维护,可以积累一下。这样就不需要遍历两次二叉树了,而是在一次遍历的过程中来不断维护maxcount和结果集。

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

题目链接

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

思想

从下往上遍历,处理顺序可以从下往上遍历,可以用回溯来实现。应该用后序遍历,左右中,回溯到中。
注意审题,每个节点的数值都是不一样的。
在这里插入图片描述
如图所示,p和q的相对位置有两种情况,第一种情况很好想到;第二种情况,p是q的祖先,那么p是p和q的最近公共祖先。
递归三部曲:

  1. 参数和返回值
  2. 确定终止条件:如果传回来的是空 return root;如果找到了p或者q,就把root返回。
  3. 单层递归逻辑:
    左:向左遍历,记得用一个参数接返回值。
    右:向右遍历,使用参数接返回值。
    中:
    如果两个返回值都不为空,此事的root就是最近公共祖先,把root返回。
    如果left空,right不为空,返回right。
    如果left不为空,right为空,返回left。
    如果两边都为空,返回NULL。

题解

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (root == NULL || root == p || root == q) return root;
        TreeNode* left = lowestCommonAncestor(root->left, p, q);
        TreeNode* right = lowestCommonAncestor(root->right, p, q);
        if (left != NULL and right != NULL) return root;
        if (left == NULL && right != NULL) return right;
        if (left != NULL && right == NULL) return left;
        else return NULL;
    }
};
class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> '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 is not None and right is not None:
            return root
        if left is None:
            return right
        return left  
        

反思

注意分析两种情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值