LeetCode - 24. Swap Nodes in Pairs 两两交换链表中节点
这题应该注意交换的是节点对象,而不是交换节点的数值。
每交换一对节点的时候,这对节点的前一个指节点和后一个节点都会涉及到。我们在这题中把一对节点的前一个节点为基准(cur节点)来对后面两个节点进行交换。这题的重点主要是交换节点的步骤以及终止条件。如果遇到的是奇数个节点,那么最后一个节点就没法交换,这时候就应该停止循环。
判断终止条件时还有一个细节,就是如果使用的短路与,那么cur.next != null必须写在第一个,如果先判断cur.next.next != null则有可能空指针异常。
个人在这种涉及可能中途会导致链表断裂的题目习惯在操作之前保存多个涉及到的temp节点,这样在交换的过程中照着画图的逻辑不容易出错。
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummy = new ListNode(-1);
dummy.next = head;
ListNode cur = dummy;
while (cur.next != null && cur.next.next != null) {
ListNode temp1 = cur.next;
ListNode temp2 = cur.next.next;
ListNode temp3 = cur.next.next.next;
cur.next = temp2;
temp2.next = temp1;
temp1.next = temp3;
cur = cur.next.next;
}
return dummy.next;
}
}
LeetCode - 19. Remove Nth Node From End of List 删除链表的倒数第N个节点
想要找倒数第N个节点,光用一个指针来直接找到是不可能的,因为链表必须从head来一个个往后找而不能从链表尾部开始循环。这题为双指针思路,fast和cur都从dummy节点开始,快指针fast先移动n个位置,再同时移动cur和fast,因为目标节点和最后一个节点的距离是确定的,注意cur指针指向的应当是删除目标的前一个节点,这样才能进行删除操作。
涉及到链表中的距离的题目还是要考画图才能更直观的知道每一个点的作用,具体位置,以及while判断的时候的边界处理。
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(-1);
dummy.next = head;
ListNode cur = dummy;
ListNode fast = dummy;
while (n > 0 && fast.next != null) {
fast = fast.next;
n--;
} //先移动快指针
while (fast.next != null) {
cur = cur.next;
fast = fast.next;
} //cur和fast同时移动
cur.next = cur.next.next; //删除指针
return dummy.next;
}
}
LeetCode - 160. Intersection of Two Linked Lists 链表相交
注意这里的相交是节点相等,而不是单纯数值相等。首先比较简单的思路,就是算出两个链表的长度差值n,让长的那个链表先走n步使得两个链表的两个指针在同一起跑线进行移动,循环后可以直接判断是否有交点;
进阶一点的思路就是把两个链表相连接的长度一定是相等的,因为A+B的长度也等于B+A,遍历完其中的一个链表时就转到另一个链表上。这个写法对于没有交点的情况并不会出现死循环不能正常返回null,因为最后两个指针一定是相等的,判断条件也会停止,也就是两个指针都是null的情况即返回null。但注意循环条件是p1 != null 而不是p1.next != null,否则就跳过了最后一个节点。
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode p1 = headA;
ListNode p2 = headB;
while (p1 != p2) {
if (p1 != null) {
p1 = p1.next;
} else {
p1 = headB; // switch to another list
}
if (p2 != null) {
p2 = p2.next;
} else {
p2 = headA;
}
}
return p1;
}
}
LeetCode - 142. LinkedList Cycle II 环形链表
这题是在链表是否有环的问题上的一个进阶,需要找出环的起点。
首先判断链表是否有环,需要用快慢指针来判断,如果有环那么快慢指针必定会相遇,只不过这个相遇点可能在环中的任何位置。假如快指针每次走两步,慢指针每次走一步,那么快指针的相对速度就是一步,无论快指针在环里转了多少圈,相遇之前一定是快指针去追慢指针的一个过程,因此不可能出现刚好跳过慢指针的情况。并且快指针一定是已经转了一圈以上才和慢指针相遇的。
至于环的入口位置,因为时间是一样的,那么根据路程/速度=时间我们可以得出一个等式:
假设快指针在转一圈后就相遇(n=1)的极端情况,可以证明得到x=z,因此x=z在不论n等于多少的情况下都是成立的。只要找到这个规律,这道题的代码逻辑就很简单,即相遇后把其中一个点回归原点,另一个点从相遇点以同样速度出发最后两个指针就会相遇在环的入口处。
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast = head, slow = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
//meet here
if (slow == fast) {
slow = head;
//move with same pace
while(slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
}
return null;
}
}