两两交换链表中的节点
两种解法都很值得学习,第二种解法可以增强对dummy节点的理解
参考链接24. 两两交换链表中的节点 - 力扣(LeetCode)
方法一,递归
class Solution {
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode next = head.next;
//以两个节点为单位分割,例如 3 4 1 2 ,此时 head = 3, next = 4
//再调用 swapPairs(next.next) 让 1 和 2 进行调换
//因为 3 4 调换成 4 3 那么此时 head.next(3.next) 正好连接后面的子单元
head.next = swapPairs(next.next);
// 4.next 连接 3完成调换
next.next = head;
return next;
}
}
方法二,设置虚拟头指针操作
- 通过day03和该解法 总结小规律,在对链表进行对换(修改位置)操作时(pre,cur,next)
- 通常先将pre节点与next节点连接(pre.next = next) & 并保存好next.next(start.next = next.next)之后,再更改cur节点(这道题pre -> temp/ cur -> start/ next -> end)
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode pre = new ListNode(0);
pre.next = head;
ListNode temp = pre;
while(temp.next != null && temp.next.next != null) {
ListNode start = temp.next;
ListNode end = temp.next.next;
temp.next = end;
start.next = end.next;
end.next = start;
temp = start;
}
return pre.next;
}
}
删除链表的倒数第N个结点
- 保存dummy结点,始终指向head
- 通过双指针相差n个索引,快指针先移动n位,然后同时移动快指针和慢指针,当快指针达到末尾时,慢指针刚好和快指针差n位
- 注意:此时慢指针所在的位置是倒数第n位的前一位
- 例;… 3 4 5 6,要删除倒数第2位,那么 6 -> 5 -> 4 ,当前慢指针所在的位置是4,是倒数第三位
- 根据链表删除的原理 slow.next = slow.next.next即可
02.07链表相交
- 假设ab链表相交,那么它们的末尾距离相交位置的长度是相同的,设为C
- 那么a -> 链表末尾 -> b头部 -> 相交点 行走的距离是 a + b - c
- b运行同理
- 遍历速度相同,行走距离相同,如果ab相交最后会在相交点相遇即 pA = pB
- 如果不相交最后都会遍历到末尾 即 null == null也可结束循环
环形链表二
思路见注释
public class Solution {
public ListNode detectCycle(ListNode head) {
//快慢指针 fast = 2 * slow,设环的长度为c,fast走2s,slow走s,头部到环入口的距离为a,相遇时fast比slow多走n圈
//相遇时 s = a + xb 2s = a + (x+n)b 2a + 2xb = a + (x+n)b -> a + xb - nb = 0 -> s = nb,
// 也就是说slow走的路程,和fast多走的路程相同,那么将fast重置到头结点并将其速度变为1,两个指针再继续运动
//当"fast"到达 环入口时,"slow"走的路程为 nb + a 也刚好在入口,那么此时两个指针指向的就是环的入口
ListNode fast = head, slow = head;
while(true){
if(fast == null || fast.next == null) return null;
fast = fast.next.next;
slow = slow.next;
if(fast == slow) break;
}
fast = head;
while(slow != fast){
slow = slow.next;
fast = fast.next;
}
return fast;
}
}