Howtofindonthebinarytree,howtofindonthebinarysearchtree?找modeset的时候有个trick,因为题目中可以有多个mode,所以一般的方法需要遍历两次才能找到modenumbers的集合。但是可以遍历一次找到模式集,及时使用清空结果集的方法。这个方法还是很巧妙的。相信仔细阅读文章的同学都会惊叹其巧妙之处!给定一个具有相同值的二叉搜索树(BST),找到BST中的所有模式(出现频率最高的元素)。假设BST有如下定义:节点左子树包含的节点的值小于或等于当前节点的值节点右子树包含的节点的值大于或等于当前节点的值左子树和右子树所有的树都是二叉搜索树。例如:给定BST[1,null,2,2],返回[2]。提示:如果mode超过1,输出顺序不需要考虑Advanced:你不需要使用额外的空间吗?(假设不计算递归产生的隐式调用栈的开销)至于思考的话题,我从两个维度讲一下递归的方法。首先如果不是二叉搜索树怎么解决,如果是二叉搜索树怎么解决,两种方法的对比可以加深大家对二叉树的理解。如果递归的方法不是二叉查找树,最直观的方法肯定是遍历树,用map统计频率,对频率排序,最后取前面高频元素的集合。具体步骤如下:树已经遍历完了,不重要用map统计频次。使用前中后序遍历并不重要,因为要遍历一个整体,任何遍历方式都可以,层次顺序遍历也没有错!这里先序遍历,代码如下://mapkey:元素,value:出现频率voidsearchBST(TreeNode*cur,unordered_map&map){//先序遍历if(cur==NULL)return;map[cur->val]++;//统计元素频率searchBST(cur->left,map);searchBST(cur->right,map);return;}得到频率统计ofoccurrence(即map)有些同学可能想直接对map中的值进行排序,但是确实不行。如果你在C++中使用std::map或者std::multimap,你可以对key进行排序,但是你不能对values进行排序。。所以需要把map转成数组,也就是vector,然后排序。当然pair代码也放在vector中,如下:boolstaticcmp(constpair&a,constpair&b){returna.second>b.second;//按频率从大到小排序}vector>vec(map.begin(),map.end());sort(vec.begin(),vec.end(),cmp);//对频率进行排序,取前面的高频元素。此时,tarrayvector已经存储了按照频率排序的pairs,所以只需要取出前面的高频元素即可。代码如下:result.push_back(vec[0].first);for(inti=1;i&map){//前序遍历if(cur==NULL)return;map[cur->val]++;//统计元素频率searchBST(cur->left,map);searchBST(cur->right,map);return;}boolstaticcmp(constpair&a,constpair&b){returna.second>b.second;}public:vectorfindMode(TreeNode*root){unordered_mapmap;//key:元素,value:出现频率vectorresult;if(root==NULL)returnresult;searchBST(root,map);vector>vec(map.begin(),map.end());sort(vec.begin(),vec.end(),cmp);//对频率进行排序result.push_back(vec[0].first);for(inti=1;ileft);//左边(处理节点)//中间searchBST(cur->right);//右边返回;}遍历有序数组中元素的出现频率,从头开始遍历,则mustIt就是比较相邻的两个元素,然后输出频率最高的元素。关键是在有序数组上好办,但是在树上怎么办呢?这是为了检查对树的操作。在二叉树:搜索树的最小绝对差中,我们用到了pre指针和cur指针的tricks,这次又用到了。获取指向前一个节点的指针,这样每次cur(当前节点)都可以与pre(前一个节点)进行比较。而初始化的时候pre=NULL,所以当pre为NULL的时候,我们就知道这是比较的第一个元素。代码如下:if(pre==NULL){//第一个节点count=1;//频率为1}elseif(pre->val==cur->val){//同值thepreviousnodecount++;}else{//与上一个节点的值不同count=1;}pre=cur;//更新上一个节点,此时出现问题,因为元素集合中频率最大的是必须的(注意是集合,不是元素,可以有多种模式),如果是数组,一般怎么办?应该先遍历数组找到出现频率最大的(maxCount),然后再遍历数组,将出现频率为maxCount的元素放入集合中。(因为有多种模式)这个方法遍历数组两次。然后我们遍历二叉搜索树两次,也可以算出模式集。但是在这里,你只需要遍历一次就可以找到所有的模式。那么如何只遍历一次呢?如果frequencycount等于maxCount(最大频率),当然要在结果集中加入这个元素(下面的代码就是结果数组),代码如下:if(count==maxCount){//如果和最大值相同,就把它放到result中result.push_back(cur->val);}是不是觉得这里有问题,result怎么容易把元素放进去,万一,这个maxCount并不是此时真正的最大频率。所以下面的操作应该是这样进行的:当频率计数大于maxCount时,不仅要更新maxCount,还要清空结果集(下面的代码是结果数组),因为结果集前面的元素都是无效的。if(count>maxCount){//如果计数大于最大值maxCount=count;//更新最大频率result.clear();//很关键的一步,不要忘记清除结果,前面result中的元素都是invalidresult.push_back(cur->val);}关键代码都写完了,完整代码如下:(只需要遍历一次二叉搜索树,找到mode的集合numbers)classSolution{private:intmaxCount;//最大频率intcount;//统计频率TreeNode*pre;vectorresult;voidsearchBST(TreeNode*cur){if(cur==NULL)return;searchBST(cur->left);//left//middleif(pre==NULL){//第一个节点count=1;}elseif(pre->val==cur->val){//与前一个节点count相同的值++;}else{//与上一个节点值不同count=1;}pre=cur;//更新上一个节点if(count==maxCount){//如果与最大值相同则放入结果result.push_back(cur->val);}if(count>maxCount){//如果count大于最大值frequencymaxCount=count;//更新最大频率result.clear();//很关键的一步,别忘了清空result,之前result中的元素无效result.push_back(cur->val);}searchBST(cur->right);//右返回;}public:vectorfindMode(TreeNode*root){count=0;maxCount=0;TreeNode*pre=NULL;//记录上一个节点结果.clear();searchBST(root);returnresult;}};迭代法只需要将中序遍历转化为迭代即可,中间节点的处理逻辑完全相同。二叉树前中后序迭代,传送门:二叉树:前中后序迭代法遍历,而中间的处理逻辑有点没变(我直接贴递归方法的代码,连注释都没变,哈哈)代码如下:classSolution{public:vectorfindMode(TreeNode*root){stackst;TreeNode*cur=root;TreeNode*pre=NULL;intmaxCount=0;//最大频率intcount=0;//统计频率向量result;while(cur!=NULL||!st.empty()){if(cur!=NULL){//访问节点的指针,访问最底层st.push(cur);//将访问过的节点入栈cur=cur->left;//Left}else{cur=st.top();st.pop();//inif(pre==NULL){//第一个节点count=1;}elseif(pre->val==cur->val){//与前面的节点值相同count++;}else{//与前面的n不同odevaluecount=1;}if(count==maxCount){//如果与最大值相同,则放入结果result.push_back(cur->val);}if(count>maxCount){//如果计数大于最大频率maxCount=count;//更新最大频率result.clear();//很关键的一步,别忘了清空结果,之前结果中的元素是全部失败result.push_back(cur->val);}pre=cur;cur=cur->right;//right}}returnresult;}};在递归的方法中总结这道题,我给出了如果是普通的二叉树,我们应该怎么求模。当我知道普通二叉树的方法后,我会进一步给出如何找到二叉搜索树的模式。如此鲜明的对比,相信我会对二叉树有更深的理解。在递归遍历二叉搜索树的过程中,我还引入了一种统计出现频率最高的元素集合的技巧。否则,需要遍历二叉搜索树两次,找出出现频率最高的元素集合。没有这个技巧为什么要遍历两次呢?因为需要的是一套,所以会有多种模式。如果只有一种模式,那么遍历一次是安全的。最后还是给出相应的迭代方法。其实就是迭代法中中序遍历的模板加上递归法中中间节点的处理逻辑。分分钟可以写完。我直接从递归方法中粘贴中间逻辑的代码。在这里。二叉查找树求众数其实是一道简单的题,但是大家可以发现我写了这么大一篇文章来讲解,主要是尽可能从各个角度来分析这道题,帮助大家更快更深入的理解.二叉树。需要强调的是,Leetcode上的耗时统计是很不准确的,粗略看一下,同一段代码的耗时差异可以达到50%以上,所以不要拿耗时统计对Leetcode太认真了,只知道理论上效率好坏。其他语言版本Java暴力法classSolution{publicint[]findMode(FindModeInBinarySearchTree.TreeNoderoot){Mapmap=newHashMap<>();Listlist=newArrayList<>();if(root==null)returnlist.stream().mapToInt(Integer::intValue).toArray();//获得频率MapsearchBST(root,map);List>mapList=map.entrySet().stream().sorted((c1,c2)->c2.getValue().compareTo(c1.getValue())).collect(Collectors.toList());list.add(mapList.get(0).getKey());//把频率最高的加入listfor(inti=1;imap){if(curr==null)return;map.put(curr.val,map.getOrDefault(curr.val,0)+1);searchBST(curr.left,map);searchBST(curr.right,map);}}classSolution{ArrayListresList;intmaxCount;intcount;TreeNodepre;publicint[]findMode(TreeNoderoot){resList=newArrayList<>();maxCount=0;count=0;pre=null;findMode1(root);int[]res=newint[resList.size()];for(inti=0;imaxCount){resList.clear();resList.add(rootValue);maxCount=count;}elseif(count==maxCount){resList.add(rootValue);}pre=root;findMode1(root.right);}}Python递归方法classSolution:deffindMode(self,root:TreeNode)->List[int]:ifnotroot:returnsself.pre=rootself.count=0//统计频率self.countMax=0//最大频率self.res=[]deffindNumber(root):ifnotroot:returnNone//第一个节点findNumber(root.left)//左边ifself.pre.val==root.val://middle:与前一个节点self相同的值。count+=1else://与上一个节点值不同self.pre=rootself.count=1ifself.count>self.countMax://如果计数大于最大频率self.countMax=self.count//更新最大Frequencyself.res=[root.val]//更新reselifself.count==self.countMax://如果和最大值相同,则放入resself.res.append(root.val)findNumber(root.right)//右returnfindNumber(root)returnsself.res迭代方式-中序遍历-不使用额外空间,使用二叉搜索树特性classSolution:deffindMode(self,root:TreeNode)->List[int]:stack=[]cur=rootpre=NonemaxCount,count=0,0res=[]whilecurorstack:ifcur:#访问节点的指针,访问栈底.append(cur)cur=cur.leftelse:#逐一处理节点cur=stack.pop()ifpre==None:#第一个节点count=1elifpre.val==cur.val:#与前一个节点count+=1else:count=1ifcount==maxCount:res.append(cur.val)ifcount>maxCount:maxCount=countres.clear()res.append(cur.val)pre=curcur=cur.rightreturnres