1.<tag-排序和数组, 链表>-lt.215-数组中的第K个最大元素 + lt.148-排序链表(待完善)
lt.215-数组中的第K个最大元素
[案例需求]
[思路分析]
- 本题出现频率非常的高!!!
- 数组中的第K最大, 最小, 或者说中位数, 都可以用各种排序方法先对数组排序, 然后返回要求的值即可;
- 所以嘛, 熟练掌握快排(迭代的, 递归的), 堆排序, 归并排序(迭代的, 递归的)非常有必要!!!, 当然了链表的各种快排, 归并排序也是必要的, 就在下面一道题.
具体的解析和详细代码可看笔者之前的一篇文章: 点我
[效率比较]
lt.148-排序链表
[案例需求]
[思路分析一, 优先队列]
-
有没有这么一种神奇的数据结构, 它能够存入一些数据, 在拿出来的时候这些数据就是有序的了, 他肯定是一种集合容器;
-
目前最常用的通过匿名内部类的方式添加比较器对象的, 其实也就TreeSet和PriorityQueue两种, 但是TreeSet会自动的对存入的数据去重, 而PriorityQueue就可以存入重复的数据.
-
本题我们采用优先队列 PriorityQueue, 为什么用这个?
可以通过类构造器传入自定义比较器, 但是TreeSet 也可以呀!
可以存入重复元素, 哈哈, TreeSet就不行啦!
/**
* 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 {
public ListNode sortList(ListNode head) {
//排序链表
//4-->2-->1-->3
//优先队列
if(head == null)return null;
PriorityQueue<ListNode> queue = new PriorityQueue<>(new Comparator<ListNode>(){
public int compare(ListNode node1, ListNode node2){
return node1.val - node2.val;
}
});
//遍历链表, 放入优先队列;
ListNode temp = head;
while(true){
if(temp == null)break;
queue.add(temp);
temp = temp.next;
}
ListNode dummyNode = new ListNode(-1);
ListNode temp1 = dummyNode;
while(queue.size() != 0){
ListNode node = queue.poll();
node.next = null; //取出结点, 并断开结点的next域
temp1.next = node;
temp1 = temp1.next;
}
return dummyNode.next;
}
}
[思路分析二, 单链表的快速排序]
链表快排!!! 也是相当的重要啦!
[思路分析三, 单链表的归并排序]
/**
* 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 {
public ListNode sortList(ListNode head) {
if (head == null) {
return null;
}
ListNode mid = getMid(head);
if (mid.next == null) {
return mid;
}
ListNode headB = mid.next;
mid.next = null;
return mergeTwoList(sortList(head), sortList(headB));
}
public ListNode getMid(ListNode head) {
head = new ListNode(0, head);
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
public ListNode mergeTwoList(ListNode l1, ListNode l2) {
ListNode dump = new ListNode();
ListNode last = dump;
while (l1 != null && l2 != null) {
if (l1.val <= l2.val) {
last.next = l1;
l1 = l1.next;
} else {
last.next = l2;
l2 = l2.next;
}
last = last.next;
}
if (l1 != null) {
last.next = l1;
}
if (l2 != null) {
last.next = l2;
}
return dump.next;
}
}
[复杂度分析]
N为链表的长度, 时间复杂度为O(NlogN), 空间复杂度为O(logN)
这道题考察的点很多,有链表归并,有获取链表的中间节点等等,每一个考点都可以作为一道题来进行考察。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)