设计一个找到数据流中第K大元素的类(class)。注意是排序后的第K大元素,不是第K个不同的元素。
你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器,它包含数据流中的初始元素。每次调用 KthLargest.add,返回当前数据流中第K大的元素。
示例:
使用PriorityQueue 优先队列,默认优先队列的作用是能保证每次取出的元素都是队列中权值最小的。
PriorityQueue
Queue maxHeap = new PriorityQueue<>(Comparator.reverseOrder());
可以转换为大堆。
思路:构建大小为k的queue,size 小于 k时候进队,大于k时候,添加值与queue.peek (第一个元素)进行比较,若大则将queue出队后再添加进去。
最后返回队第一个元素peek,即为k大的值。
class KthLargest {
PriorityQueue queue ;
int k = 0;
public KthLargest(int k, int[] nums) {
this.k = k;
queue = new PriorityQueue<Integer>();
for(int num : nums) {
if(queue.size() < k) {
queue.offer(num);
}else {
if(num > (int)queue.peek()) {
queue.poll();
queue.add(num);
}
}
}
}
public int add(int val) {
if(queue.size() < k) {
queue.add(val);
}else {
if(val > (int)queue.peek()) {
queue.poll();
queue.add(val);
}
}
return (int)queue.peek();
}
}
利用构建二叉搜索树来查找。
思路:
判断根节点是第几大值,因为右子树都比root都大,右子树节点个数加1,则就是root是第几大值。
1、首先将数组构造成二叉搜索树,树的属性多了一个count,来计数本节点与子节点个数总和。
2、查找第k大的节点值,首先查找root,pos = root.right.count + 1 代表root.val 是第pos大的值,如果 k = pos 直接返回root.val就可以。不相等则判断去左右子树中继续寻找。
3、若 k > pos 。 则说明 要找比 root的小的值,故去 node = root.left 子树中寻找。这时候需要更新k值,k = k - pos,代表需要在左子树中找到第k大的节点。
同样 node 在左子树中节点大小位子为 pos = node.right.count + 1,与 k 在进行比较,相等则返回,不等继续寻找
4、若k < pos 。说明要找比root大的值,故去 node = root.right中寻找。同样 node 在右子树中节点大小位子为 pos = node.right.count + 1,k 与 pos 比较。 k 不需要更新。
迭代寻找
class TreeNode {
int val, count = 1;
TreeNode left, right;
TreeNode(int v) { val = v; }
}
class KthLargest {
TreeNode root;
int k;
public KthLargest(int k, int[] nums) {
this.k = k;
for(int i = 0; i < nums.length; i++){
root = addNode(root,nums[i]); //创建并添加二叉搜索树
}
}
public int add(int val) {
root = addNode(root,val);
return findKthLargest();
}
public TreeNode addNode(TreeNode root, int val){ //将节点添加到二叉搜索树中
if(root == null) return new TreeNode(val);
TreeNode temp = new TreeNode(val);
TreeNode node = root;
while(true){
node.count++; //节点每增加一个孩子 则count ++ ;
if(node.val > val){
if(node.left == null){
node.left = temp;
break;
}else{
node = node.left;
}
}else{
if(node.right == null){
node.right = temp;
break;
}else{
node = node.right;
}
}
}
return root;
}
//找第k大的节点值。
public int findKthLargest(){
int count = k;
TreeNode node = root;
while(count > 0){
int pos = 1 + (node.right != null ? node.right.count : 0); // pos 代表在以本节点为根的树中,是pos大
if(pos == count) break; //找到节点
if(count > pos){ //count 比pos 大 代表需要找比pos位子小的树,则取左子树继续找
node = node.left;
count = count -pos; //更新count,继续找左子树中第count大的节点
}else{
node = node.right;
}
}
return node.val;
}
}