合并K个升序链表中的优先队列:
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 1:
输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6
示例 2:
输入:lists = []
输出:[]
示例 3:
输入:lists = [[]]
输出:[]
题解:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
class CustomComparator implements Comparator<ListNode> {
public int compare(ListNode l1, ListNode l2) {
int value = l1.val - l2.val;
if (value >= 0) return 1;
else return -1;
}
}
PriorityQueue<ListNode> que = new PriorityQueue<>(new CustomComparator());//默认小根堆
public ListNode mergeKLists(ListNode[] lists) {
for (ListNode node : lists) {//取出各链表头节点放入小根堆
if (node != null)
que.offer(node);
}
ListNode dummyHead = new ListNode(0);
ListNode cur = dummyHead;
while (!que.isEmpty()) {
ListNode top = que.poll();
cur.next = top;
cur = cur.next;//cur = cur.next = top;
if (top.next != null) que.offer(top.next);
}
return dummyHead.next;
}
}
其中实现小根堆也可以这样写:
PriorityQueue<ListNode> que = new PriorityQueue<>(new Comparator<ListNode>() {
public int compare(ListNode l1, ListNode l2) {
int value = l1.val - l2.val;
if (value >= 0) return 1;
else return -1;
}
});//小根堆
比较方法的实现:
Comparable
和Comparator
在Java中都是用于对象比较和排序的接口,但它们之间存在一些重要的区别。
- 实现位置:
Comparable
接口是一个内置于java.lang
包中的接口,通常需要在类的定义中实现它。当类实现了Comparable
接口时,该类的对象就具有了一个自然的比较顺序。Comparator
接口则是一个位于java.util
包中的接口,它通常用于那些没有实现Comparable
接口的类,或者即使实现了但也需要不同的比较逻辑的情况。Comparator
接口允许我们为类的实例提供外部的比较逻辑。
- 方法定义:
Comparable
接口定义了一个compareTo(T o)
方法,该方法接受一个与当前对象类型相同的参数,并返回一个整数,表示当前对象与参数对象之间的比较结果。Comparator
接口定义了一个compare(T o1, T o2)
方法,该方法接受两个类型相同的参数,并返回一个整数,表示这两个对象之间的比较结果。
- 排序规则:
- 对于实现了
Comparable
接口的类,其排序规则是在类的内部定义的,即每个对象都知道如何与其他同类型的对象进行比较。 - 对于使用
Comparator
接口的排序,排序规则是在类的外部定义的,即我们可以为同一类型的对象定义多个不同的比较逻辑。
- 对于实现了
- 使用场景:
- 当类具有自然的比较顺序(如数字、字符串等)时,应该实现
Comparable
接口。 - 当需要为对象提供自定义的比较逻辑时,应该使用
Comparator
接口。例如,你可能想要根据对象的某个特定属性或组合属性进行排序,而这些属性并不是该对象的自然顺序。
- 当类具有自然的比较顺序(如数字、字符串等)时,应该实现
- 与集合类的交互:
- 当使用如
Arrays.sort()
或Collections.sort()
等方法对集合进行排序时,如果集合中的元素实现了Comparable
接口,则可以直接调用这些方法。 - 如果集合中的元素没有实现
Comparable
接口,但提供了Comparator
对象,则可以在调用排序方法时将该Comparator
对象作为参数传递。
- 当使用如
总结来说,Comparable
和Comparator
都用于对象的比较和排序,但它们在实现位置、方法定义、排序规则、使用场景以及与集合类的交互方面有所不同。
用法示例:
//在Java中,如果你有一个链表(例如使用LinkedList)并且你想根据链表中的元素进行排序或比较,你需要定义一个比较器(Comparator)或者让链表中的元素实现Comparable接口。
//使用Comparator
//如果你不想修改链表元素的类定义,或者元素的类不是你可以修改的,你可以定义一个Comparator来对链表进行排序或比较。
import java.util.Comparator;
import java.util.LinkedList;
class MyElement {
int value;
// 构造函数、getter、setter等
}
public class Main {
public static void main(String[] args) {
LinkedList<MyElement> list = new LinkedList<>();
// 假设你已经向list中添加了一些MyElement对象
Comparator<MyElement> comparator = new Comparator<MyElement>() {
@Override
public int compare(MyElement o1, MyElement o2) {
return Integer.compare(o1.value, o2.value);
}
};
// 使用Comparator进行排序
list.sort(comparator);
}
}
//实现Comparable接口
//如果你可以修改链表元素的类定义,并且你想让这个类的实例自然可排序(即不需要额外的比较器),你可以让该类实现Comparable接口。
import java.util.LinkedList;
class MyElement implements Comparable<MyElement> {
int value;
// 构造函数、getter、setter等
@Override
public int compareTo(MyElement other) {
return Integer.compare(this.value, other.value);
}
}
public class Main {
public static void main(String[] args) {
LinkedList<MyElement> list = new LinkedList<>();
// 假设你已经向list中添加了一些MyElement对象
// 直接使用sort方法,因为MyElement已经实现了Comparable接口
list.sort(null); // 在这种情况下,你可以传递null作为sort方法的参数,因为列表元素是可比较的
}
}