这里记录刷hot100的思考过程详解,方便后续记忆复习。
题号215
给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。
具体题解
java
class Solution {
public int findKthLargest(int[] nums, int k) {
List<Integer> numList=new ArrayList<>();
for(int num:nums){
numList.add(num);
}
return quickselect(numList,k);
}
public int quickselect(List<Integer> numList,int k){
Random rand=new Random();
int pivot=numList.get(rand.nextInt(numList.size()));
List<Integer> small=new ArrayList<>();
List<Integer> big=new ArrayList<>();
List<Integer> equal=new ArrayList<>();
for(int num:numList){
if(num>pivot){
big.add(num);
}else if(num<pivot){
small.add(num);
}else{
equal.add(num);
}
}
if(k<=big.size()){
return quickselect(big,k);
}
if(big.size()+equal.size()<k){
return quickselect(small,k-big.size()-equal.size());
}
return pivot;
}
}
思路解析
找第k大的元素,基于三路分区快速选择算法解决。找第K大元素即为找从小到大排序后的第K个元素,在这里先找一个基准值把元素划分为big,equal,small三组,然后判断要找的元素在哪一组,不断递归。
必会知识
1.通过随机选取基准值来提高算法时间复杂度的稳定性。
java
Random random=new Random();
int pivot=numList.get(random.nextInt(numList.size()));
题号347
给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
具体题解
java
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer,Integer> hashmap =new HashMap<>();
for(int num:nums){
hashmap.put(num,hashmap.getOrDefault(num,0)+1);
}
Queue<int []> queue=new PriorityQueue<>(new Comparator<int []>(){
@Override
public int compare(int[] m,int[] n){
return m[1]-n[1];
}
});
for(Map.Entry<Integer,Integer> entry:hashmap.entrySet()){
int num=entry.getKey(),count=entry.getValue();
if(queue.size()==k){
if(queue.peek()[1]<count){
queue.poll();
queue.offer(new int[]{num,count});
}
}else{
queue.offer(new int[]{num,count});
}
}
int[] ans=new int[k];
for(int i=0;i<k;i++){
ans[i]=queue.poll()[0];
}
return ans;
}
}
思路解析
通过hashmap存储元素与出现次数的关系,然后实现基于出现次数排序的最小堆。对hashmap进行遍历,在堆中只存储出现次数最多的k个。这里细节较多。
必会知识
1.通过getOrDefault存储出现次数
2.通过Comparator实现最大堆
java
Queue<int []> queue=new priorityQueue<>(new Comparator<>(){
@Override
public int compare(int[] x,int[] y){
return x[1]-y[1];
}
});
3.遍历hashmap
java
for(Map.Entry<Integer,Integer> entry:hashmap.entrySet()){
int num=entry.getKey(),count=entry.getValue;
}
题号295
中位数是有序整数列表中的中间值。如果列表的大小是偶数,则没有中间值,中位数是两个中间值的平均值。
- 例如
arr = [2,3,4]的中位数是3。 - 例如
arr = [2,3]的中位数是(2 + 3) / 2 = 2.5。
实现 MedianFinder 类:
-
MedianFinder()初始化MedianFinder对象。 -
void addNum(int num)将数据流中的整数num添加到数据结构中。 -
double findMedian()返回到目前为止所有元素的中位数。与实际答案相差10-5以内的答案将被接受。
具体题解
java
class MedianFinder {
Queue<Integer> maxQueue;
Queue<Integer> minQueue;
public MedianFinder() {
maxQueue=new PriorityQueue<>((x,y)->(y-x));
minQueue=new PriorityQueue<>();
}
public void addNum(int num) {
if(maxQueue.size()!=minQueue.size()){
maxQueue.offer(num);
minQueue.offer(maxQueue.poll());
}else{
minQueue.offer(num);
maxQueue.offer(minQueue.poll());
}
}
public double findMedian() {
return maxQueue.size()!=minQueue.size()?maxQueue.peek()
:(maxQueue.peek()+minQueue.peek())/2.0;
}
}
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder obj = new MedianFinder();
* obj.addNum(num);
* double param_2 = obj.findMedian();
*/
思路解析
用最大堆存储数据的前一半,最小堆存储数据的后一半,最终只会使用到两个堆的堆顶数据。最奥妙的部分是,利用最大堆or最小堆内部排序算法对新来数据排序。最终实现如果想添加数到最大(小)堆,那么先添加到最小(大)堆
必会知识
自定义最大堆
