数据结构与算法(LeetCode刷题记录及相应知识点整理,含题解及顺序 Java版)//..
文章目录
数据结构与算法(LeetCode刷题记录及相应知识点整理,含题解及顺序 Java版)
一. 链表
1) 21.合并两个有序链表 (简单) 2021.10.9
/**
* 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 mergeTwoLists(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(-1), p = dummy;
ListNode p1 = l1, p2 = l2;
// -1 也可写成 0/1 其他数
// 区分 == 和 =
// 根据测验 最后return的 不能是p.next 需要是dummy.next才可以 区别在于p在代码体中出现了. dummy没 (还待考证)
while(p1 != null && p2 != null) {
if(p1.val < p2.val) {
p.next = p1;
p1 = p1.next;
}else {
p.next = p2;
p2 = p2.next;
}
p = p.next;
}
if(p1 != null) {
p.next = p1;
}
if(p2 != null) {
p.next = p2;
}
return dummy.next;
}
}
技巧1: 虚节点
2) 23. 合并K个升序链表 (困难) 2021.10.13
第一次:
弄了很久, 但还是存在一些问题
要再多仔细弄弄 把细节弄清楚
小黄鸭法
心得:
不会的知识 一点一点查 耐心坚持总会做出来的
/**
* 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 mergeKLists(ListNode[] lists) {
解法一: 优先队列
if(lists.length == 0) {
return null;
}
ListNode dummy = new ListNode(-1);
ListNode p = dummy;
PriorityQueue<ListNode> pq = new PriorityQueue<>((a, b) -> a.val - b.val);
/*
PriorityQueue<ListNode> pq = new PriorityQueue<>(new Comparator<ListNode>() {
@Override
public int compare(ListNode a, ListNode b) {
return a.val - b.val;
}
});
*/
for(ListNode head : lists) {
if (head != null) {
pq.add(head);
}
}
while(!pq.isEmpty()) {
ListNode node = pq.poll();
p.next = node;
if(node.next != null) {
pq.add(node.next);
}
p = p.next;
}
return dummy.next;
/*
if (lists.length == 0) {
return null;
}
// 虚拟头结点
ListNode dummy = new ListNode(-1);
ListNode p = dummy;
// 优先级队列,最小堆
PriorityQueue<ListNode> pq = new PriorityQueue<>((a, b)-> a.val - b.val);
// 将 k 个链表的头结点加入最小堆
for (ListNode head : lists) {
if (head != null)
pq.add(head);
}
while (!pq.isEmpty()) {
// 获取最小节点,接到结果链表中
ListNode node = pq.poll();
p.next = node;
if (node.next != null) {
pq.add(node.next);
}
// p 指针不断前进
p = p.next;
}
return dummy.next;
*/
解法二:
}
}
优先队列pq
中的元素个数最多是k,所以一次poll
或者add
方法的时间复杂度是 O(logk),所有链表节点都会被加入和弹出pq
,所以算法的整体时间复杂度是:
时间复杂度为 O(Nlogk)
N:链表的节点总数
k:链表条数
相关知识点补充
一. 链表
1) 链表和数组的区别及优缺点
区别:
(1)内存:数组静态分布内存,链表动态分布内存;
数组在内存中是连续的,链表不连续;
(2)复杂度:
①查找时:
数组利用索引定位,查找的时间复杂度是O(1),
链表通过遍历定位元素,查找的时间复杂度是O(n);
② 插入和删除:
数组插入和删除要移动其他元素, 时间复杂度是O(n),
链表的插入和删除不需要移动其他元素, 时间复杂度是O(1);
数组的优缺点:
(1)优点:
复杂度: 随机访问性比较强,可以通过下标进行快速定位。查找速度快
(2)缺点:
内存: ①会造成内存的浪费. 因为内存是连续的,所以在创建数组的时候必须规定其大小,如果不合适,就会造成内存的浪费。
②内存空间要求高. 创建一个数组,必须要有足够的连续内存空间。
③数组的大小是固定的,在创建数组的时候就已经规定好,不能动态拓展, 如果要扩容, 需要重新分配一块更大的空间, 再把所有数据全部复制过去.
复杂度: ④插入和删除的效率低,需要移动其他元素。
链表的优缺点:
(1)优点:
内存: ①内存利用率高,不会浪费内存,可以使用内存中细小的不连续的空间,只有在需要的时候才去创建空间。大小不固定,拓展很灵活。
复杂度: ②插入和删除的效率高,只需要改变指针的指向就可以进行插入和删除。
(2)缺点:
内存: ①由于每个元素必须存储指向前后元素位置的指针, 会消耗相对更多的存储空间.
复杂度: ②查找的效率低,因为链表是从第一个节点向后遍历查找。
适用场景:
数组: 数据量固定, 频繁查找, 较少删改
链表: 数据量不固定, 频繁增删, 较少查询
2) 优先队列
①Java中重写优先队列比较器2021.10.21
//匿名内部类
PriorityQueue<Integer> queue = new PriorityQueue<>(new Comparator<Integer>(){
@Override
public int compare(Integer o1, Integer o2){
//如果认为o1优先级比o2高,先出o1 compare返回<0的整数
//如果认为o2优先级比o1高,先出o2 compare返回>0的整数
//如果一样,返回0
return o2-o1;
}
});
/*
原理就是
结果为-,返回前面的一个元素o1
结果为+,返回后面的一个元素o2
上面是将小根堆换成了大根堆,小根堆就是return o1-o2
*/
待看
fucking-algorithm/刷题技巧.md at master · labuladong/fucking-algorithm · GitHub
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下