代码随想录算法训练营第四天 | 24.两两交换链表中的节点,19.删除链表的倒数第N个节点 ,142.环形链表II ,160.链表相交 9.24
链表解题思路总结
- 首先想用什么方法去遍历链表 双指针还是单指针
- 然后想指针从哪里开始
- 然后想实现功能操作如何实现 指针需要在哪个位置
- 然后想循环结束的条件
- 然后想返回值 取哪个
24. 两两交换链表中的节点
- 想让两个节点交换位置 操作指针需要指在他们两个节点的前一个节点 这点非常重要
- 第二 如何判断循环结束条件
- 当节点个数为奇数个时,到最后时cur.next.next为空 即最后一个就不用交换位置了
- 当节点个数为偶数个时,cur后面没有节点,因此 判断cur.next为空
- 因此循环条件为 cur.next!=null && cur.next.next!=null
- cur.next必须写前面 这样如果为空就不会执行后面的cur.next.next也就不会报空指针异常错误
- 交换操作 需用temp
- 然后移动cur指针到后两位 cur.next.next
- 最后返回新链表的头节点 dummyhead.next
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummyhead = new ListNode(-1,head);
ListNode cur = dummyhead;
while(cur.next!=null && cur.next.next!=null){
ListNode temp1 = cur.next;
ListNode temp2 = cur.next.next.next;
cur.next = cur.next.next;
cur.next.next = temp1;
cur.next.next.next = temp2;
cur = cur.next.next;
}
return dummyhead.next;
}
}
19.删除链表的倒数第N个节点
- 这题的关键点是如何定位到倒数第n个节点前一个节点
- 可以用双指针的方法 先让快指针跑n个节点 然后快慢指针同时跑 直到快指针.next==Null 这样慢指针就到了
- 这题也需要使用虚拟头节点的方法 因为可能要删除的节点就是头节点
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummyhead = new ListNode(-1,head);
ListNode slow = dummyhead;
ListNode fast = dummyhead;
while(n!=0){
fast = fast.next;
n--;
}
while(fast.next!=null){
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return dummyhead.next;
}
}
142.环形链表II
如何判断是否有环
- 定义快慢两个指针 fast一次走2个节点 slow一次走一个节点 这样快指针相对于慢指针每次走 1个节点
这样就不会错过慢指针
寻找环的入口
- x表示从链表头节点到入口距离 y表示从入口到相遇点距离 z表示从相遇点再到入口距离
- 慢指针路程可以表示为x+y 快指针路程可以表示为x+n(y+z)
- 因为慢指针一次1格 快指针一次2格 所以有等式 2(x+y)=x+n(y+z) 取n=1 即 x=z
- 为什么慢指针路程可以表示为x+y? 因为慢指针在环里面一圈还没有转到就与快指针相遇了 因为快指针速度为慢指针的两倍
所以必定快指针必定能在一圈之内与慢指针相遇 - 由x=z 可以在头节点定义Index1 相遇点定义index2 然后让他们往前走 等到他们相遇 就刚好走到入口点 再返回index1或index2就可以了
- 控制快指针慢指针向后跳 的循环终止条件 为 快指针 fast不为空 fast.next也不为空 因为有可能 fast跳完2格自己是空的
然后fast.next就会空指针报错
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast = head;
ListNode slow = head;
while(fast!=null && fast.next!=null){
fast = fast.next.next;
slow = slow.next;
if(fast==slow){
ListNode index1 = head;
ListNode index2 = fast;
while(index1!=index2){
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}
return null;
}
}
160.链表相交
- 注意,交点不是数值相等,而是指针相等
- 注意到 要想找两个链表的初始交点 从每个链表前面开始遍历的话是不可行的
- 所以可以先分别求出A B链表的长度 然后求出两个链表的长度的差值
- 然后就可以让长的链表先遍历差值 与短的链表处于相平齐的位置
- 接下来同时遍历移动找相等节点即可
- 若一直没找到 则循环结束返回null
- 为什么不从后往前遍历 因为链表只知道头指针head 所以只能从前往后遍历
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode cur;
cur = headA;
int lenA = 0;
while(cur!=null){
cur = cur.next;
lenA++;
}
int lenB = 0;
cur = headB;
while(cur!=null){
cur = cur.next;
lenB++;
}
ListNode cura;
ListNode curb;
int minus = Math.abs(lenA-lenB);
if(lenA>lenB){
cur = headA;
}else{
cur = headB;
}
while(minus!=0){
cur = cur.next;
minus--;
}
if(lenA>lenB){
cura = cur;
curb = headB;
}else{
curb = cur;
cura = headA;
}
while(cura!=null){
if(cura!=curb){
cura = cura.next;
curb = curb.next;
}else{
return cura;
}
}
return null;
}
}