假设这棵树不是二叉搜索树,是一棵普通的树,则递归法如下:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
//如果这棵树不是一棵二叉搜索树
class Solution {
public:
void searchBST(TreeNode* cur,unordered_map<int,int>& mymap){
if(cur==nullptr) return;
mymap[cur->val]++;//统计元素出现的频率,利用[]做插入操作,如果已经存在键值,
//则会作赋值修改操作,如果没有则插入
searchBST(cur->left,mymap);
searchBST(cur->right,mymap);
}
//sort中的比较函数compare要声明为静态成员函数或全局函数,不能作为普通成员函数
//非静态成员函数是依赖于具体对象的,而std::sort这类函数是全局的,
//因此无法再sort中调用非静态成员函数。
//静态成员函数或者全局函数是不依赖于具体对象的, 可以独立访问,
//无须创建任何对象实例就可以访问。同时静态成员函数不可以调用类的非静态成员
bool static cmp(const pair<int,int>& a,const pair<int,int>& b){
return a.second>b.second;//降序排列
}
vector<int> findMode(TreeNode* root) {
vector<int> result;
if(root==NULL) return result;
unordered_map<int,int> mymap;// key:元素, value:出现频率
//第一步,利用map统计出这棵树每个结点元素出现的次数
searchBST(root,mymap);
//第二步,由于map只能对key排序,不能对value排序,所以要把map转换为数组vector,
//在进行排序。
//vec初始化,容器里要存放的元素类型和mymap容器中的一样,值为mymap中全部元素
vector<pair<int,int>> vec(mymap.begin(),mymap.end());
//sort默认升序排序,但此时容器里存放的不是基本数据类型,是一个pair,排序方式需要我们自己定义,并且需要降序排序
sort(vec.begin(),vec.end(),cmp);//给频率排序
//第三步,此时数组vector中已经是存放着按照频率排好序的pair,
//那么把前⾯⾼频的元素取出来就可以了
result.push_back(vec[0].first);//第一个元素才是节点值
for(int ii=1;ii<vec.size();ii++){
if(vec[ii].second==vec[0].second) result.push_back(vec[ii].first);// 取最⾼的放到result数组中
else break;
}
return result;
}
};
如果这棵树是二叉搜索树,则递归法如下:
二叉搜索树的中序遍历是有序的
输出:123456
中序遍历代码:
void searchBST(TreeNode* cur){
if(cur==NULL) return;
searchBST(cur->left); //左
//处理节点 //中
searchBST(cur->right); //右
}
遍历有序数组的元素出现频率,从头遍历,那么⼀定是相邻两个元素作⽐较,然后就把出现频率最⾼的元素输出就可以了。
遍历二叉树我们也可以弄⼀个指针指向前⼀个节点,这样每次cur(当前节点)才能和pre(前⼀个节点)作⽐较。⽽且初始化的时候pre = NULL,这样当pre为NULL时候,我们就知道这是⽐较的第⼀个元素。
代码如下:
if(pre==NULL){//第一个节点
count=1; //频率为1
}else if(pre->val==cur->val){//与前一个节点数值相同
count++;
}else{ //与前一个节点不同
count=1;
}
pre=cur;//更新pre节点
此时⼜有问题了,因为要求最⼤频率的元素集合(注意是集合,不是⼀个元素,可以有多个众数),如果是数组⼤家⼀般怎么办?
应该是先遍历⼀遍数组,找出最⼤频率(maxCount),然后再重新遍历⼀遍数组把出现频率为maxCount的元素放进集合。(因为众数有多个)这种⽅式遍历了两遍数组。
那么我们遍历两遍⼆叉搜索树,把众数集合算出来也是可以的。但这⾥其实只需要遍历⼀次就可以找到所有的众数。那么如何只遍历⼀遍呢?如果 频率count 等于 maxCount(最⼤频率),当然要把这个元素加⼊到结果集中(以下代码为result数组),这个方法叫做适时清空结果集的⽅法代码如下:
if(count>maxCount){// 如果计数⼤于最⼤值
maxCount=count;// 更新最⼤频率
result.clear();// 很关键的⼀步,不要忘记清空result,之前result⾥的元素都失效了
result.push_back(cur->val);
}
完整代码:
class Solution{
private:
int count; // 统计频率
int maxCount; // 最⼤频率
TreeNode* pre=NULL;
vector<int> 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;// 更新上⼀个节点
// 如果和最⼤值相同,放进result中
if(count==maxCount) result.push_back(cur->val);//先判断相等情况,因为下面会改变maxCount的值
if(count>maxCount){// 如果计数⼤于最⼤值频率
maxCount=count;// 更新最⼤频率
result.clear();// 很关键的⼀步,不要忘记清空result,之前result⾥的元素都失效了
result.push_back(cur->val);
}
searchBST(cur->right);// 右
}
public:
vector<int> findMode(TreeNode* root) {
result.clear();
if(root==NULL) return result;
count=0;
maxCount=0;
searchBST(root);
return result;
}
};
迭代法
只需把中序遍历转换成迭代
class Solution{
public:
vector<int> findMode(TreeNode* root){
vector<int> result;
if(root==NULL) return result;
int count=0;
int maxCount=0;
TreeNode* pre=NULL;
TreeNode* cur=root;
stack<TreeNode*> st;
while(cur!=NULL||!st.empty()){
if(cur!=NULL){
st.push(cur);
cur=cur->left;
}else{
cur=st.top();
st.pop();
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);
}
cur=cur->right;
}
}
return result;
}
};
总结:
如果是普通⼆叉树,应该怎么求众数。
如果是⼆叉搜索树⼜应该怎么求众数。
在递归遍历⼆叉搜索树的过程中,介绍了⼀个统计最⾼出现频率元素集合的技巧, 要不然就要遍历两次⼆叉搜索树才能把这个最⾼出现频率元素的集合求出来。
为什么没有这个技巧⼀定要遍历两次呢? 因为要求的是集合,会有多个众数,如果规定只有⼀个众数,那么就遍历⼀次稳稳的了。