题目二:
解法一:(递归 | 普通二叉树)
如果不是二叉搜索树,最直观的方法一定是把这个树都遍历了,用map统计频率,然后根据频率来进行筛选。
完整代码如下:
var findMode = function(root) {
// 使用递归中序遍历
let map = new Map();
// 1. 确定递归函数以及函数参数
const traverTree = function(root) {
// 2. 确定递归终止条件
if(root === null) {
return ;
}
traverTree(root.left);
// 3. 单层递归逻辑
map.set(root.val,map.has(root.val)?map.get(root.val)+1:1);
traverTree(root.right);
}
traverTree(root);
//上面把数据都存储到map
//下面开始寻找map里面的
// 定义一个最大出现次数的初始值为root.val的出现次数
let maxCount = map.get(root.val);
// 定义一个存放结果的数组res
let得res = [];
for(let [key,value] of map) {
// 如果当前值等于最大出现次数就直接在res增加该值
if(value === maxCount) {
res.push(key);
}
// 如果value的值大于原本的maxCount就清空res的所有值,因为找到了更大的
if(value>maxCount) {
res = [];
maxCount = value;
res.push(key);
}
}
return res;
};
解法二:(递归 | 二叉搜索树)
既然是搜索树,它中序遍历就是有序的。
var searchBST = function(cur) {
if (cur == NULL) return ;
searchBST(cur.left); // 左
(处理节点) // 中
searchBST(cur.right); // 右
return ;
}
遍历有序数组的元素出现频率,从头遍历,那么一定是相邻两个元素作比较,然后就把出现频率最高的元素输出就可以了。
关键是在有序数组上的话,好搞,在树上怎么搞呢?
在二叉树:搜索树的最小绝对差 (opens new window)中我们就使用了pre指针和cur指针的技巧,这次又用上了。
用一个指针指向前一个节点,这样每次cur(当前节点)才能和pre(前一个节点)作比较。
而且初始化的时候pre = NULL,这样当pre为NULL时候,我们就知道这是比较的第一个元素。
if (pre == NULL) { // 第一个节点
count = 1; // 频率为1
} else if (pre.val == cur.val) { // 与前一个节点数值相同
count++;
} else { // 与前一个节点数值不同
count = 1;
}
pre = cur; // 更新上一个节点
此时又有问题了,因为要求最大频率的元素集合(注意是集合,不是一个元素,可以有多个众数),如果是数组上大家一般怎么办?
应该是先遍历一遍数组,找出最大频率(maxCount),然后再重新遍历一遍数组把出现频率为maxCount的元素放进集合。(因为众数有多个)
这种方式遍历了两遍数组。
那么我们遍历两遍二叉搜索树,把众数集合算出来也是可以的。
但这里其实只需要遍历一次就可以找到所有的众数。
那么如何只遍历一遍呢?
如果 频率count 等于 maxCount(最大频率),当然要把这个元素加入到结果集中(以下代码为result数组),代码如下:
if (count == maxCount) { // 如果和最大值相同,放进result中
result.push(cur.val);
}
是不是感觉这里有问题,result怎么能轻易就把元素放进去了呢,万一,这个maxCount此时还不是真正最大频率呢。
所以下面要做如下操作:
频率count 大于 maxCount的时候,不仅要更新maxCount,而且要清空结果集(以下代码为result数组),因为结果集之前的元素都失效了。
if (count > maxCount) { // 如果计数大于最大值
maxCount = count; // 更新最大频率
result = []; // 很关键的一步,不要忘记清空result,之前result里的元素都失效了
result.push(cur.val);
}
完整代码:
var findMode = function(root) {
let res = []
let pre = null // 记录前一个结点
let count = 0 // 统计频率
let maxCount = 0 // 最大频率
var inOrder = function(cur) {
if (cur === null) {
return
}
inOrder(cur.left) // 左
// 中
if (pre === null) {
count = 1
}else if (pre.val === cur.val) { // 与前一个节点数值相同
count++
} else {
count = 1 // 与前一个节点数值不同
}
pre = cur // 更新上一个节点
if (count === maxCount) { // 如果和最大值相同,放进res中
res.push(cur.val)
}
if (count > maxCount) { // 如果计数大于最大值频率
maxCount = count // 更新最大频率
res = [] // 很关键的一步,不要忘记清空result,之前result里的元素都失效了
res.push(cur.val)
}
inOrder(cur.right) // 右
}
inOrder(root)
return res
};
解法三:(迭代法)
同递归解法,只是改为迭代法,中间处理逻辑一致。
var findMode = function(root) {
let stack = []
let pre = null
let cur = root
let res = []
let count = 0
let maxCount = 0
while (cur || stack.length) {
if (cur) {
stack.push(cur)
cur = cur.left
} else {
cur = stack.pop()
if (!pre) {
count = 1
} else if (pre.val === cur.val) {
count++
} else {
count = 1
}
pre = cur
if (count === maxCount) {
res.push(cur.val)
}
if (count > maxCount) {
maxCount = count
res = []
res.push(cur.val)
}
cur = cur.right
}
}
return res
};