题意理解:
首先明确: 二叉搜索树中序遍历是严格的单调递增序列,也就是说,传统意义上得到二叉搜索树不存在相同的数,也不可能存在众数。
所以: 这里的二叉搜索树不是严格意义上的二叉搜索树,它允许重复的值,其中序遍历是不严格的单调增的序列。
又因为: 二叉搜索树是不严格的单调增序列,所以其相同的值总是挨着的
所以: 我们能从前后不相同的两个值为一个起始点,统计相同数的个数
所以: 我们能维护一个最大的count在整个遍历在整个过程中,并保存对应的元素值
解题思路:
对应两种树的遍历思路: 递归 迭代
1.递归
中间节点的处理逻辑是:
pre的值等于cur的值时,统计当前元素的count,否则count开启重置count=1
对maxCount进行更新:
若当前count==maxCount,则当前root的值进入结果集
若当前count>maxCount,则当前结果集清空,root的值进入结果集,maxCount=count,值更新
若当前count<maxCount,无操作
/*** 这里找二叉搜索树的众数,首先明确,正常的二叉搜索数不存在重复的数据,其中序遍历是严格单调增序列* 所以,这里的二叉树是非常规的二叉树,它允许重复的值,重复的值总是存在于左子树* 同时又因为二叉搜索树中序遍历是有序的,所以重复的数总是挨着的,可以一个起始点开始count++,统计出现次数* @param root* @return*///保存结果List<Integer> resultList=new ArrayList<>();//双指针,是想前一个节点TreeNode pre=null;//记录当前元素重复次数int count=0;//记录最大重复次数int maxCount=0;//递归解法public int[] findMode(TreeNode root) {//中序遍历//左子树处理if(Objects.nonNull(root.left)) findMode(root.left);//中间节点处理if(pre==null||pre.val!=root.val){count=1;}else{count++;}//最大count更新if(maxCount<count){resultList.clear();resultList.add(root.val);maxCount=Math.max(maxCount,count);}else if(maxCount==count){resultList.add(root.val);}// 节点推移pre=root;//右子树处理if(Objects.nonNull(root.right)) findMode(root.right);//list转数组return resultList.stream().mapToInt(Integer::intValue).toArray();}
2.迭代
迭代和递归的中间处理逻辑是相同的,只是使用自定义栈来模拟递归过程,来防止栈溢出
//迭代解法public int[] findMode2(TreeNode root){List<Integer> resultList=new ArrayList<>();//双指针,是想前一个节点TreeNode pre=null;//记录当前元素重复次数int count=0;//记录最大重复次数int maxCount=0;//自定义栈Stack<TreeNode> stack=new Stack<>();stack.push(root);while(!stack.isEmpty()){TreeNode cur=stack.peek();if(cur!=null){stack.pop();//中序入栈,有因为栈总是先进后出的,所以以一下顺序入栈//对子树进行非空判断后入栈,则子树不会导致null值入栈//手动null值入栈,是一个信号,即下一个值为中间节点,一定是非空的,进行识别并处理if(Objects.nonNull(cur.right)) stack.push(cur.right);stack.push(cur);stack.push(null);if(Objects.nonNull(cur.left)) stack.push(cur.left);}else{stack.pop();cur=stack.pop();//获得中间节点,中间节点的处理逻辑if(pre==null||pre.val!=cur.val) count=1;else count++;if(maxCount==count){resultList.add(cur.val);} else if (maxCount<count) {resultList.clear();resultList.add(cur.val);maxCount=count;}pre=cur;}}return resultList.stream().mapToInt(Integer::intValue).toArray();}
3.分析
时间复杂度:
递归:O(n)
迭代:O(n)
空间复杂度:
递归:O(1)
迭代:O(n)