(1)在Java中比较两个元素相等用equals方法
(2)比叫自定义对象的大小关系时,类重写Comparable接口,实现compareTo方法
若一个类Student implents Comparable,则这个Student类具备了可比较的能力
public comparareTo(Object o){ } ,比较当前对象和传入对象的大小关系
①当返回值>0时,当前元素"大于"传入对象o
②当返回值<0时,当前元素"小于"传入对象o
③当返回值=0时,当前元素"等于"传入对象o
package priority_queue.compare;
import java.util.Arrays;
public class Student implements Comparable {
private int age;
private String name;
public Student(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
@Override
public int compareTo(Student o) {
return this.age-o.age;
}
public static void main(String[] args) {
Student[] arr=new Student[]{
new Student(19,"张三"),
new Student(20,"李四"),
new Student(18,"王麻子")
};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
}
}
(3)实现java.until.comparator 接口=>比较器接口
此时进行排序就会到的一个升序的数组,但如果此时要得到一个降序的数组就要改为" o.age-this.age",在程序设计模式中提到,一段程序应该对扩展开放,对修改关闭,就是说当出现新的要求时,尽量不要去影响已经写好的代码,而是用新的代码去完成新要求
java.until.Comparator接口:
一个类如果实现了这个接口,就表示这个类天生就是为别的类的大小关系服务的
StudentSec这个类天生就是为了Student对象的排序而存在的,并且重写了cpmparr方法
传入两个值o1和o2比较他们的大小关系
①当返回值大于0时,说明o1>o2
②当返回值小于0时,说明o1
③当返回值等于0时,说明o1=o2
package priority_queue.compare;
import java.util.Arrays;
import java.util.Comparator;
class StudentSec implements Comparator{
@Override
public int compare(Student o1, Student o2) {
return o1.getAge()-o2.getAge();
}
}
class StudentDesc implements Comparator{
@Override
public int compare(Student o1, Student o2) {
return o2.getAge()-o1.getAge();
}
}
public class Student {
private int age;
private String name;
public int getAge() {
return age;
}
public Student(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
public static void main(String[] args) {
Student[] arr=new Student[]{
new Student(19,"张三"),
new Student(20,"李四"),
new Student(18,"王麻子")
};
//此时Student不具备比较的能力,但是可以通过比较器去比较
Arrays.sort(arr,new StudentSec());
System.out.println(Arrays.toString(arr));
Arrays.sort(arr,new StudentDesc());
System.out.println(Arrays.toString(arr));
}
}
可以看出来此时就不需要在原来的代码进行修改,需要什么样的比较方法,就产生一个新的类专门去实现,极大程度上实现了java的开闭原则
package priority_queue;
import queue.Queue;
public class PriorityQueue implements Queue {
private MaxHeap heap;
public PriorityQueue(){
heap=new MaxHeap();
}
@Override
public void offer(Integer val) {
heap.add(val);
}
@Override
public Integer poll() {
return heap.extractMax();
}
@Override
public Integer peek() {
return heap.peekMax();
}
@Override
public boolean isEmptty() {
return heap.isEmpty();
}
}
leetcode面试题17.14
看到题的第一种想法是使用排序然后取出前k个值就可以,但是此时的时间复杂度0(nlogn),假如此时要求时间复杂优于O(nlogn),那么排序就行不通了,就要用到优先级队列
TOPK问题都可以用优先级队列去解决,若需要取出前k个最大元素就构造最小堆,若需要取出前k个最小元素就构造最大堆
思路:取出最小的k个元素,构造一个大小为k的最大堆
①若此时堆中的元素
②若此时堆中的元素=k
a.新来的元素val>=堆顶元素,一定大于此时堆中的所有元素,则val一定不是需要的元素
b.新来的元素val<堆顶元素,将堆顶元素出队,将新元素添加到堆中
c.重复上述操作,直到没有新元素为止,此时堆中就是前k个最小值
package priority_queue.leetcode;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;
/**
* 设计一个算法,找出数组中最小的k个数。以任意顺序返回这k个数均可
*/
class IntegerReverse implements Comparator{
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
}
public class Num17_14 {
public int[] smallestK(int[] arr, int k) {
int[] ret=new int[k];
if (arr.length==0||k==0){
return ret;
}
//JDK是默认使用最小堆,所以我们要将其改造为最大堆,通过比较器实现
Queue queue=new PriorityQueue<>(new IntegerReverse());
//遍历集合,堆中只保存k个元素
for (int i = 0; i < arr.length; i++) {
if (queue.size()
优先级队列要保存的元素是键值对时,当现有的类型无法解决问题时,就自定义一个类
package priority_queue.leetcode;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Queue;
/**
* 前 K 个高频元素
*/
//自定义一个类,此时类中保存了数组中的元素以及出现的频次
class kind implements Comparable{
//数组中出现的元素
int key;
//元素出现的频次
int frequency;
public kind(int key, int frequency) {
this.key = key;
this.frequency = frequency;
}
@Override
public int compareTo(kind o) {
return this.frequency-o.frequency;
}
}
public class Num347 {
public int[] topKFrequent(int[] nums, int k) {
int[] ret=new int[k];
//先遍历数组,将出现的元素次数以及频次保存到Map集合中
Map map=new HashMap<>();
for (int i:nums){
if (map.containsKey(i)){
//此时i元素已经出现过,就将频次++
int times=map.get(i);
map.put(i,times+1);
}else{
//此时i元素第一次出现,就将该元素保存到map集合中
map.put(i,1);
}
}
//经过集合的遍历之后,将出现频次最高的前k个元素添加到优先级队列中
Queue queue=new PriorityQueue<>();
for (Map.Entryentry : map.entrySet()){
if (queue.size()kind.frequency){
queue.poll();
queue.offer(new kind(entry.getKey(), entry.getValue()));
}
}
}
//此时堆中就保存了前k个出现频次最大的键值对,遍历堆,将key取出
int i=0;
while (!queue.isEmpty()){
ret[i]=queue.poll().key;
i++;
}
return ret;
}
}
利用和上一个题相同的思路,首先明确优先级队列中该保存什么?
优先级队列中应该保存两个元素v1和v2,其中v1来自第一个数组,v2来自第二个数组,此时优先级中的"大小"关系就应该有v1和v2的加和大小判断,因为题目要求就是找到和最小的k个数对
注意:双循环的终止条件,从题目中可以知道两个数组都是排序好的升序数组,所以当要求去找出和最小的k对数组时,当k大于数组长度时,也就是示例3来说,就是将数组中的所有数都返回,当k小于等于数组长度时,只返回前k对数就行,总结循环的条件就是数组长度和k的最小值
https://gitee.com/ren-xiaoxiong/rocket_class_ds/tree/master/src/priority_queue/https://gitee.com/ren-xiaoxiong/rocket_class_ds/tree/master/src/priority_queue/