目录
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集合类,比上面两种方法更加的容易简洁,总之呢,为了以后的学习和工作,全部学会掌握还是很有必要的。