题目一:19. 删除链表的倒数第 N 个结点❤
题目思路
核心思想:典型的双指针题目
定义两个指针,其中一个快指针先走 n 或者 n+1 步,具体的区别后面说明,然后再将快指针和慢指针同时向前移动,直到快指针走到链表的尾部null处为止,此时,如果最开始快指针走了 n 步,那么此时的慢指针指向的节点就是待删除的节点,如果最开始快指针走了 n+1 步,此时慢指针指向的就是待删除节点的上一个节点。
如果快指针走 n 步,此时需要额外定义一个变量保存慢指针指向节点的前一个节点,因为快指针指向链表尾部null时,慢指针指向的就是待删除节点,而如果想要删除待删除节点,需要通过它的上一个元素进行删除,因此有必要在移动慢指针前先保存一下他的前一个节点。
如果快指针走 n+1 步,此时当快指针指向链表尾部null时,慢指针指向的就是待删除元素的上一个节点,此时直接删除慢指针指向的下一个节点即可,具体方法
slow.next = slow.next.next
。
题解代码
/*
fast先走n步以后,再和慢指针同时走,
直到fast指针走到链表最后的null处,此时slow对应的就是待删除的节点
*/
public ListNode removeNthFromEnd(ListNode head, int n) {
// 哨兵节点
ListNode s = new ListNode(-1, head);
ListNode fast = s.next; // 快指针
ListNode slow = s.next; // 慢指针
ListNode prev = s;
// fast先走n步,需要额外定义一个prev指针指向待删除节点的上一个节点
for (int i = 0; i < n; i++) {
fast = fast.next;
}
while (fast != null) {
fast = fast.next;
// 每次移动slow节点,先记录下来当前slow再移动,此时的prev就是slow节点的前一个节点
prev = slow;
slow = slow.next;
}
// 将slow节点删除
prev.next = slow.next;
return s.next;
}
---------------------------------------------------------------------------------------------
/*
fast先走n+1步以后,再和慢指针同时走,
直到fast指针走到链表最后的null处,此时slow对应的就是待删除节点的上一个节点
*/
public ListNode removeNthFromEnd2(ListNode head, int n) {
// 哨兵节点
ListNode s = new ListNode(-1, head);
ListNode fast = s;
ListNode slow = s;
// fast先走n+1步,不需要额外定义一个prev指针指向待删除节点的上一个节点
for (int i = 0; i < n + 1; i++) {
fast = fast.next;
}
while (fast != null) {
fast = fast.next;
slow = slow.next;
}
// 将slow指针指向的下一个节点从链表中删除
slow.next = slow.next.next;
return s.next;
}
题目二:面试题 02.07. 链表相交
题目思路
-
双指针:定义两个指针,其中一个指针(currA)遍历链表A,另一个指针(currB)遍历链表B,当currA遍历完链表A后,将其指向链表B的头节点继续遍历链表B,同理,currB指针在遍历完链表B后指向链表A的头结点继续遍历链表A
因此我们只需要在死循环中判断两指针如果相同,则返回其中一个指针指向的节点即可。(无论有没有相交,最终两指针都会相同,不需要考虑死循环问题)
-
如果链表A和链表B有相交节点,则指针currA和currB会同时到达相交节点
-
如果没有相交节点,则两个指针会同时指向null
-
题解代码
/*
A链表走完走B链表,B链表走完走A链表,如果有相交在循环一次以后一定会同时到达相交节点
如果没有相交会走完A和B链表同时到达NULL
*/
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode currA = headA;
ListNode currB = headB;
while (true) {
// 无论是否有无相交,都会在该循环最后走到A,B两个指针相等
// 有交点,同时指向相交节点 返回相交节点
// 无交点,同时指向null节点 返回null
if (currA == currB) {
return currA;
}
if (currA == null) {
currA = headB; // 走完A链表走B链表
} else {
currA = currA.next;
}
if (currB == null) {
currB = headA; // 走完B链表走A链表
} else {
currB = currB.next;
}
}
}