链表定义
链表的遍历
ListNode p=head; while(p!=null) p=p.next;
找到链表的尾结点
p=head; while(p.next!=null)p=p.next;
链表节点的个数
p=head; cnt=0; //cnt与p不同步对应
while(p!=null):cnt++; p=p.next
cnt与p不同步对应的原因:
while停止后,p为null,cnt为对应到最后一个节点上面
规律:开始的时候同步和结束时候的同步规律是一致的。
链表删除
注意:1.删除节点需要dummyNode 2.最后返回的是dummyNode.next而不是head.
因为head可能被删掉
ListNode dummyNode=new ListNode();
dummyNode.next=head;
(p.next为待删除节点)
p.next=p.next.next;
return dummyNode.next;
链表插入
(1)头插法: dummyNode,p:
(2)尾插法
在尾插法的过程中,tail.next不需要清空:
每次插入时tail.next都会重定向到待插入的节点
最后tail.next=null
找到链表的第index个节点
链表翻转
指定区间反转链表
增加虚拟头结点。
如果说从第一个开始就翻转,那么就得分情况讨论,所以要添加一个虚拟头结点。
两个链表第一个公共的节点
(1)求两个链表长度n1,n2
(2)长的链表走|n1-n2|步,使两个链表长度相同
(3)两个链表一起走,相等返回,走到头返回null
倒数第k个节点
(1) 求节点个数n
(2)求第n-k+1个节点
删除重复节点
(1)增加虚拟头结点
(2)链表节点的删除
p.next=p.next.next
删除链表倒数第n个节点
(1)添加虚拟头结点
(2)求链表长度l
(3)找第l-n的节点并删除
判断环
如果有环:slow和fast走一定会相遇
如果没有环:在有限次遍历链表后,一定为空
判断环的入口
(1)fast和slow置头结点,速度为2,1
(2)相遇后fast置头结点,速度为1
(3)fast和slow相遇的节点是入口
合并两个排序的链表
回文链表
存储链表的值
奇偶链表
给定单链表的头节点 head
,将所有索引为奇数的节点和索引为偶数的节点分别组合在一起,然后返回重新排序的列表。 O(1)
的额外空间复杂度和 O(n)
的时间复杂度
两个虚拟头结点,使用尾插法,然后合并到一起。
尾插法最后置空,否则会出现野指针错误。
LeetCode 25 k个一组翻转链表
使用栈,进栈k次,尾插法就是逆序的。需要考虑剩下的链表个数够不够 k
个(因为不够 k
个不用翻转)。已经翻转的部分要与剩下链表连接起来。
LeetCode 23 合并 K 个升序链表
使用优先队列。
分析时间复杂度:
- 初始化优先队列:将所有链表的头节点加入优先队列的时间复杂度为 O(k),其中 k 是链表数组
lists
的长度,这是因为每个节点仅需一次入队操作。 - 主循环:每次循环中,我们执行一次弹出操作(O(log k)),然后可能执行一次入队操作(O(log k))。由于每个链表中的节点最多会被入队和弹出各一次,且总共有 n 个节点(n 是所有链表节点总数),因此主循环部分的时间复杂度为 O(n log k)。
- 构造结果链表:此过程仅涉及指针赋值,时间复杂度可视为常数,即 O(1)。
LeetCode 143 重排链表
leetcode82 删除排序链表的重复元素||
LeetCode 2 两数相加
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。请你将两个数相加,并以相同形式返回一个表示和的链表。
有序表的归并算法:??