力扣703 - 数据流中的第k大元素

文章介绍了如何设计一个KthLargest类来找到数据流中的第k大元素,提供了使用数组排序、队列(PriorityQueue)和LinkedList三种方法的实现代码,强调了理解题意和处理细节的重要性,特别是队列和LinkedList的解决方案更为简洁易懂。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1.题目->

题目解读->

该题要注意的细节->

2.更加容易理解的代码(繁琐)

代码->

核心思想->

3.使用Queue(队列)的代码(简洁)

代码-> 

核心思想->

4.使用LinkedList集合的代码(更容易理解,相对2更为简洁)

代码->

核心思想->


1.题目->

/*设计一个找到数据流中第 k 大元素的类(class)。注意是排序后的第 k 大元素,不是第 k 个不同的元素。
        请实现 KthLargest 类:
        KthLargest(int k, int[] nums) 使用整数 k 和整数流 nums 初始化对象。
        int add(int val) 将 val 插入数据流 nums 后,返回当前数据流中第 k 大的元素。
         
        示例:
        输入:
        ["KthLargest", "add", "add", "add", "add", "add"]
        [[3, [4, 5, 8, 2]], [3], [5], [10], [9], [4]]
        输出:
        [null, 4, 5, 5, 8, 8]
        解释:
        KthLargest kthLargest = new KthLargest(3, [4, 5, 8, 2]);
        kthLargest.add(3);   // return 4
        kthLargest.add(5);   // return 5
        kthLargest.add(10);  // return 5
        kthLargest.add(9);   // return 8
        kthLargest.add(4);   // return 8*/

题目解读->

对于刚看到这一题的同学肯定会产生一些迷茫,因为这题的描述是真的low呀,不认真读,不上手看一下答案,压根不理解这题后面的答案到底是咋来的呀!而且在leetcod评论区也有好多人对这一题的描述有很大的意见,哈哈哈,但是,当你真正读懂了这一题的时候,明白了它给的案例是怎么来的,这一题就会变得很容易了。


这一题的意思用我的理解就是给你一个整型数组(也就是题目中的nums流),再给你一个数值(也就是提米中的k值),并不停的给你其他数值让你添加进该数组(使用给好的add方法),让你在添加好数值后的数组中找到在该数组中第k个最大的数 - 

例如: nums流 4 5 8 2  --- k值是3 --- 添加好按升序的数组:2 3 4 5 8

       此时的添加前的数组:2 3 4 5 8  --- k值是5 --- 添加好按升序的数组:2 3 4 5 5 8

 此时的添加前的数组:2 3 4 5 5 8 --- k值是10 --- 添加好按升序的数组:2 3 4 5 5 8 10

 此时的添加前的数组:2 3 4 5 5  8 10 --- k值是9 --- 添加好按升序的数组:2 3 4 5 5 8 9 10

 此时的添加前的数组:2 3 4 5 5 8 9 10  --- k值是4 --- 添加好按升序的数组:2 3 4 4  5 5 8 9 10

从上面的例子展示中我们就可以得到案例中的 4 5 5 8 8是怎么来的了,更加理解这个题目的意思。

该题要注意的细节->

1.当调用一次add方法添加val值进数组中的时候,该数组应该是上次调用add方法已经把上一次得val值添加后的数组,而不是刚开始给你仅仅只是nums流中的数据的数组。

2.第k个最大大小的数值,是在该数组中数据中第k个最大的值,而不是第k个值,必须要仔细的读题。


2.更加容易理解的代码(繁琐)

代码->

import java.util.Arrays;
class KthLargest {
    int k = 0;//用于接收构造方法初始化的k值
    int[] nums;//用于接收构造方法初始化的num流

    public KthLargest(int k, int[] nums) {
        //构造方法初始化k值和nums流
        this.k = k;
        this.nums = nums;
    }

    //add方法主要就是是实现把val插入已经排序好的nums流中
    public int add(int val) {
        //先把nums流进行排序
        Arrays.sort(nums);//从小到大
        //把数组拷贝进一份新的数组长度是原数组长度+1
        int[] arr = new int[nums.length + 1];
        System.arraycopy(nums, 0, arr, 0, nums.length);
        //将val插入该数组中
        int n;
        for (n = 0; n < arr.length; n++) {
            if (arr[n] >= val) {
                //把该索引后面的数据向后挪动
                //2 4 5 8
                for (int j = arr.length - 1; j > n; j--) {
                    //数据往后赋值
                    arr[j] = arr[j - 1];
                }
                break;
            }
        }
        if (n == arr.length) {
            arr[n - 1] = val;
        }
        else {
            //把val放入索引i+1的位置
            arr[n] = val;
        }
        //1 2 3 4 5
        //第k个最大元素的索引是 - 数组的长度-k
        this.nums = arr;
        return arr[arr.length - k];

    }
}

public class Test {
    public static void main(String[] args) {
        KthLargest kthLargest = new KthLargest(3, new int[]{4, 5, 8, 2});
        System.out.println(kthLargest.add(3));   // return 4  - 2 3 4 5 8
        System.out.println(kthLargest.add(5));   // return 5 - 2 3 4 5 5 8
        System.out.println(kthLargest.add(10));  // return 5 - 2 3 4 5 5 8 10
        System.out.println(kthLargest.add(9));   // return 8 - 2 3 4 5 5 8 9 10
        System.out.println(kthLargest.add(4));   // return 8 - 2 3 4 4 5 5 6 9 10
    }
}
/**
 * Your KthLargest object will be instantiated and called as such:
 * KthLargest obj = new KthLargest(k, nums);
 * int param_1 = obj.add(val);
 */

核心思想->

1.在add方法中使用System.arraycopy方法把nums流拷贝一个新的数组中,该数组的长度比nums流+1,用于存放val元素(因为数组一旦创建,长度也就固定了,想要添加元素进数组中,不能使用原数组,只能创建一个长度更大的新数组)

2.再使用Arrays.sort方法对新数组进行排序,得到一个升序(降序也可以)的数组,最后使用找到第k个大的数据对应的索引,return该值


3.使用Queue(队列)的代码(简洁)

代码-> 

import java.util.PriorityQueue;

class Slove {
    PriorityQueue<Integer> pq;
    int k;

    public Slove(int k, int[] nums) {
        this.k = k;
        pq = new PriorityQueue<Integer>();
        for (int x : nums) {
            add(x);
        }
    }

    public int add(int val) {
        pq.offer(val);
        if (pq.size() > k) {
            pq.poll();
        }
        return pq.peek();
    }
}

public class Answer {
    public static void main(String[] args) {
        Slove slove = new Slove(3,new int[]{4,5,8,2});
        System.out.println(slove.add(3));
        System.out.println(slove.add(5));
        System.out.println(slove.add(10));
        System.out.println(slove.add(9));
        System.out.println(slove.add(4));

    }
}

核心思想->

1.这个代码使用到了Queue队列实现类PriorityQueue,并在实例化对象的时候创建了集合,用于存储nums流中的数据还有val值

2.在add方法中,使用了队列中的offer插入元素方法,poll方法还有peek方法完成对整个add方法的实现。

这些方法在Api文档中都有介绍,有兴趣的小伙伴请自行去学习,这里不做过多介绍。


4.使用LinkedList集合的代码(更容易理解,相对2更为简洁)

代码->

import java.util.*;
class MySlove {
    //创建一个集合用于存入nums流的数据和add添加的val值
    LinkedList<Integer> list;
    //成员k
    int k;

    public MySlove(int k, int[] nums) {
        //创建对象的时候,创建集合对象给list引用
        list = new LinkedList<>();
        //k的值赋予全局
        this.k = k;
        //把nums数据存入集合中
        for (Integer x : nums) {
            list.addLast(x);
        }

    }

    public int add(int val) {
        //linkedList中的addLast方法能数据存入队列末尾
        list.addLast(val);
        //无序存入完后再进行排序 - lambda表达式
        list.sort((o1, o2) -> o2 - o1);//升序
        //如果长度比k小就补null
        while (list.size() < k) {
            list.addLast(null);
        }
        //返回第k大的值
        return list.get(k - 1);
    }
}

public class myAnswer {
    public static void main(String[] args) {
        MySlove slove = new MySlove(3, new int[]{4, 5, 8, 2});
        System.out.println(slove.add(3));
        System.out.println(slove.add(5));
        System.out.println(slove.add(10));
        System.out.println(slove.add(9));
        System.out.println(slove.add(4));
    }
}

核心思想->

这个代码的实现相对前面两个更加容易理解更加的简洁

1.创建LinkedList集合,通过使用LinkedList中的addLast方法把nums流中的全部数据和val值存入集合中,再使用sort方法对其进行排序,最后根据k值得到第k大的元素。

整体来说,看到这里你就会发现使用LinkedList集合类,比上面两种方法更加的容易简洁,总之呢,为了以后的学习和工作,全部学会掌握还是很有必要的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值