面试经典算法系列之二叉树12 -- 二叉搜索树中的众数

面试经典算法27 - 二叉搜索树中的众数

LeetCode.501
公众号:阿Q技术站

问题描述

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

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

假定 BST 满足如下定义:

  • 结点左子树中所含节点的值 小于等于 当前节点的值
  • 结点右子树中所含节点的值 大于等于 当前节点的值
  • 左子树和右子树都是二叉搜索树

示例 1:

输入:root = [1,null,2,2]
输出:[2]

示例 2:

输入:root = [0]
输出:[0]

思路

递归
  1. 对 BST 进行中序遍历,在遍历的过程中记录当前节点值以及出现的次数。
  2. 使用一个变量 maxCount 来记录出现次数最多的节点值的次数。
  3. 在中序遍历的过程中,如果当前节点值等于上一个节点值,则增加该节点值的出现次数;否则,更新上一个节点值的出现次数,并检查是否需要更新 maxCount
  4. 最后,再次遍历 BST,将出现次数等于 maxCount 的节点值加入结果集中。
非递归
  1. 初始化一个栈 stack 和一个哈希表 count,用于存储节点值的出现次数。

  2. 初始化一个变量 maxCount,用于记录最大出现次数。

  3. 从根节点开始,进行循环遍历直到栈为空:

    对于当前节点,如果其存在左子节点,则将其左子节点入栈,并将当前节点指向左子节点;否则,弹出栈顶节点,并进行如下处理:

    • 统计该节点值的出现次数,更新 countmaxCount
    • 如果该节点存在右子节点,则将右子节点入栈,并将当前节点指向右子节点。
  4. 遍历完成后,遍历 count,将出现次数等于 maxCount 的节点值加入结果集。

图解

今天就不给大家画图了,把这个非常详细的流程分享给大家,如果自己有不懂的地方,可以根据这个流程画一个很直观的流程图。

1. 初始化空向量 modes 和辅助栈 s
2. 如果根节点为空,返回空向量 modes
3. 初始化哈希表 count,用于存储节点值的出现次数,和最大出现次数 maxCount 为 0
4. 初始化当前节点指针 curr 为根节点
5. 循环直到当前节点为空且栈为空
   5.1. 循环直到当前节点为空
      5.1.1. 将当前节点入栈
      5.1.2. 更新当前节点为当前节点的左子节点
   5.2. 弹出栈顶节点作为当前节点
   5.3. 更新节点值的出现次数
   5.4. 更新最大出现次数
   5.5. 更新当前节点为当前节点的右子节点
6. 遍历哈希表 count
   6.1. 如果节点值的出现次数等于最大出现次数,将节点值加入向量 modes
7. 返回向量 modes

参考代码

C++
递归
#include <iostream>
#include <vector>
#include <unordered_map>

using namespace std;

// 二叉树节点的定义
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

class Solution {
public:
    // 中序遍历二叉树,同时统计每个节点值出现的次数,并找出最大出现次数
    void inorder(TreeNode* root, unordered_map<int, int>& count, int& maxCount) {
        if (!root) {
            return;
        }
        inorder(root->left, count, maxCount);

        // 统计当前节点值的出现次数
        count[root->val]++;
        maxCount = max(maxCount, count[root->val]);

        inorder(root->right, count, maxCount);
    }

    // 查找二叉搜索树中的众数
    vector<int> findMode(TreeNode* root) {
        vector<int> modes;
        if (!root) {
            return modes;
        }

        unordered_map<int, int> count; // 用于统计每个节点值出现的次数
        int maxCount = 0; // 最大出现次数

        // 中序遍历统计每个节点值的出现次数,并找出最大出现次数
        inorder(root, count, maxCount);

        // 再次中序遍历,将出现次数等于最大出现次数的节点值加入结果集中
        for (auto& entry : count) {
            if (entry.second == maxCount) {
                modes.push_back(entry.first);
            }
        }

        return modes;
    }
};

// 创建二叉树
TreeNode* createTree(vector<int>& nodes, int index) {
    if (index >= nodes.size() || nodes[index] == -1) {
        return nullptr; // 如果节点为空,则返回nullptr
    }
    TreeNode* root = new TreeNode(nodes[index]); // 创建当前节点
    root->left = createTree(nodes, 2 * index + 1); // 创建左子树
    root->right = createTree(nodes, 2 * index + 2); // 创建右子树
    return root; // 返回当前节点
}

int main() {
    vector<int> nodes = {1, 2, 2}; // 二叉搜索树的中序遍历序列
    TreeNode* root = createTree(nodes, 0); // 创建二叉树
    Solution solution;
    vector<int> modes = solution.findMode(root); // 查找众数
    for (int mode : modes) {
        cout << mode << " ";
    }
    cout << endl;

    return 0;
}
非递归
#include <iostream>
#include <vector>
#include <stack>
#include <unordered_map>

using namespace std;

// 二叉树节点的定义
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

class Solution {
public:
    vector<int> findMode(TreeNode* root) {
        vector<int> modes;
        if (!root) {
            return modes; // 如果根节点为空,直接返回空结果
        }

        stack<TreeNode*> s; // 辅助栈,用于模拟中序遍历过程
        unordered_map<int, int> count; // 用于存储节点值的出现次数
        int maxCount = 0; // 记录最大出现次数
        TreeNode* curr = root; // 当前节点指针,从根节点开始

        while (curr || !s.empty()) {
            while (curr) {
                s.push(curr); // 将当前节点入栈
                curr = curr->left; // 遍历左子树
            }

            curr = s.top(); // 获取栈顶节点
            s.pop(); // 弹出栈顶节点

            count[curr->val]++; // 统计节点值的出现次数
            maxCount = max(maxCount, count[curr->val]); // 更新最大出现次数

            curr = curr->right; // 处理右子节点
        }

        // 遍历统计结果,将出现次数等于最大出现次数的节点值加入结果集
        for (auto& entry : count) {
            if (entry.second == maxCount) {
                modes.push_back(entry.first);
            }
        }

        return modes; // 返回结果集
    }
};

// 创建二叉树
TreeNode* createTree(vector<int>& nodes, int index) {
    if (index >= nodes.size() || nodes[index] == -1) {
        return nullptr; // 如果节点为空,则返回nullptr
    }
    TreeNode* root = new TreeNode(nodes[index]); // 创建当前节点
    root->left = createTree(nodes, 2 * index + 1); // 创建左子树
    root->right = createTree(nodes, 2 * index + 2); // 创建右子树
    return root; // 返回当前节点
}

int main() {
    vector<int> nodes = {1, 2, 2}; // 二叉搜索树的中序遍历序列
    TreeNode* root = createTree(nodes, 0); // 创建二叉树
    Solution solution;
    vector<int> modes = solution.findMode(root); // 查找众数
    for (int mode : modes) {
        cout << mode << " ";
    }
    cout << endl;

    return 0;
}
Java
import java.util.*;

// 二叉树节点的定义
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    TreeNode(int x) {
        val = x;
    }
}

public class Solution {
    public int[] findMode(TreeNode root) {
        List<Integer> modes = new ArrayList<>(); // 用于存储众数的列表
        if (root == null) {
            return new int[0]; // 如果根节点为空,直接返回空数组
        }

        Stack<TreeNode> stack = new Stack<>(); // 辅助栈,用于模拟中序遍历
        Map<Integer, Integer> count = new HashMap<>(); // 用于存储节点值及其出现次数的映射
        int maxCount = 0; // 最大出现次数

        TreeNode curr = root; // 当前节点
        while (curr != null || !stack.isEmpty()) {
            while (curr != null) {
                stack.push(curr); // 将当前节点入栈
                curr = curr.left; // 遍历左子树
            }

            curr = stack.pop(); // 弹出栈顶节点
            count.put(curr.val, count.getOrDefault(curr.val, 0) + 1); // 更新节点值出现次数
            maxCount = Math.max(maxCount, count.get(curr.val)); // 更新最大出现次数

            curr = curr.right; // 处理右子节点
        }

        for (Map.Entry<Integer, Integer> entry : count.entrySet()) {
            if (entry.getValue() == maxCount) {
                modes.add(entry.getKey()); // 将出现次数等于最大出现次数的节点值加入众数列表
            }
        }

        // 将众数列表转换为数组并返回
        return modes.stream().mapToInt(Integer::intValue).toArray();
    }

    // 创建二叉树
    public TreeNode createTree(Integer[] nodes, int index) {
        if (index >= nodes.length || nodes[index] == null) {
            return null;
        }
        TreeNode root = new TreeNode(nodes[index]);
        root.left = createTree(nodes, 2 * index + 1);
        root.right = createTree(nodes, 2 * index + 2);
        return root;
    }

    public static void main(String[] args) {
        Integer[] nodes = {1, null, 2, 2};
        Solution solution = new Solution();
        TreeNode root = solution.createTree(nodes, 0);
        int[] modes = solution.findMode(root);
        for (int mode : modes) {
            System.out.print(mode + " ");
        }
        System.out.println();
    }
}
Python
from typing import List
from collections import Counter
from queue import LifoQueue
from typing import Optional

# 二叉树节点的定义
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def findMode(self, root: TreeNode) -> List[int]:
        modes = []  # 存储众数的列表
        if not root:
            return modes  # 如果根节点为空,直接返回空列表

        stack = LifoQueue()  # 辅助栈,用于模拟中序遍历
        count = Counter()  # 用于存储节点值及其出现次数的字典
        max_count = 0  # 最大出现次数

        curr = root  # 当前节点
        while curr or not stack.empty():
            while curr:
                stack.put(curr)  # 将当前节点入栈
                curr = curr.left  # 遍历左子树

            curr = stack.get()  # 弹出栈顶节点
            count[curr.val] += 1  # 更新节点值出现次数
            max_count = max(max_count, count[curr.val])  # 更新最大出现次数

            curr = curr.right  # 处理右子节点

        for key, value in count.items():
            if value == max_count:
                modes.append(key)  # 将出现次数等于最大出现次数的节点值加入众数列表

        return modes

    # 创建二叉树
    def createTree(self, nodes: List[Optional[int]], index: int) -> Optional[TreeNode]:
        if index >= len(nodes) or nodes[index] is None:
            return None
        root = TreeNode(nodes[index])
        root.left = self.createTree(nodes, 2 * index + 1)
        root.right = self.createTree(nodes, 2 * index + 2)
        return root

# 测试代码
nodes = [1, None, 2, 2]
solution = Solution()
root = solution.createTree(nodes, 0)
modes = solution.findMode(root)
print(modes)
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值