链接: 24. Swap Nodes in Pairs
此题主要还是对虚拟头节点的运用。经过简单的画图可以了解,两两交换过程中,对头两个节点的处理和其他节点的处理是略有不同的。具体如下图。
头两个节点的处理:
其他节点的处理:
可以看出来如果交换的是头两个节点,其步骤少了一步。所以这道题用虚拟节点可以简化这一问题。
做题的时候注意遍历循环的条件。
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummyHead = new ListNode(0, head);
// 因为这里一直有cur=pre.next,也可以将pre和cur合成一个变量
// 这里方便理解,可以看作同步移动的双指针,所以设置了两个变量
ListNode pre = dummyHead;
ListNode cur = head;
ListNode next;
// 如果上文只有pre一个变量,则这里的循环条件是
// pre.next!=null && pre.next.next!=null
while (cur != null && cur.next != null) {
next = cur.next;
pre.next = cur.next;
cur.next = next.next;
next.next = cur;
pre = cur;
cur = pre.next;
}
return dummyHead.next;
}
时间复杂度:O(n)
空间复杂度:O(1)
此题关键是要意识到头节点的特殊性,并通过设置虚拟头节点将特殊的头节点转换为统一性处理,大大简化代码。
代码随想录文章讲解:传送门
代码随想录视频讲解:传送门
链接: 19. Remove Nth Node From End of List
初看这题,傻傻的我,先将链表遍历了一遍,求出长度,然后再算出最后第n个是顺数第几个,再遍历一遍查找到,然后删除。
这里可以使用双指针法,设定快慢两个指针,快指针从头节点先移动n个节点,慢指针指向头节点,然后两个指针同时向后遍历,当快指针到达链表末尾的时候,慢指针就刚好指向的是倒数第n个节点啦,然后去执行删除操作。
还需注意的是,在删除节点的操作上,删除头节点和删除非头节点的处理又有差别,所以这里还是可以用到虚拟头节点来统一操作。在链表的题目里,都需要想一下头节点是否特殊,如果特殊可以考虑使用虚拟头节点。
这里我的两种解法都贴一下:
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode currentNode = head;
int count = 0;
while (currentNode != null) {
count++;
currentNode = currentNode.next;
}
ListNode dummyHead = new ListNode(0, head);
currentNode = dummyHead;
for (int i = 0; i < count - n; i++) {
currentNode = currentNode.next;
}
currentNode.next = currentNode.next.next;
return dummyHead.next;
}
}
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummyHead = new ListNode(0,head);
ListNode fast = dummyHead, slow = dummyHead;
for(int i = 0; i < n; i++){
fast = fast.next;
}
while(fast.next!=null){
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return dummyHead.next;
}
}
时间复杂度:O(n)
空间复杂度:O(1)
此题关键是要意识到头节点的特殊性,并通过设置虚拟头节点将特殊的头节点转换为统一性处理,大大简化代码。
代码随想录文章讲解:传送门
代码随想录视频讲解:传送门
链接: 面试题 02.07. Intersection of Two Linked Lists LCCI
这题需要注意一点,“Note that the intersection is defined based on reference, not value.”题目中说了,相交的交点,是引用相同而非值相同,即交点是同一个节点,而非值一样的两个节点。所以两个链表交点后的后续节点都是一模一样的。
如果两个链表一长一短,同时从头节点开始遍历,那么他们到达交点的循环轮次肯定不一样,但是如果两个链表长度相同,那么他们到达交点时,循环轮次是一样的。
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
int lenA = 0, lenB = 0;
ListNode curA = headA, curB = headB;
while (curA != null) {
curA = curA.next;
lenA++;
}
while (curB != null) {
curB = curB.next;
lenB++;
}
curA = headA;
curB = headB;
// 让curA为最长链表的头,lenA为其长度
if (lenB > lenA) {
//1. swap (lenA, lenB);
int tmpLen = lenA;
lenA = lenB;
lenB = tmpLen;
//2. swap (curA, curB);
ListNode tmpNode = curA;
curA = curB;
curB = tmpNode;
}
for (int i = 0; i < lenA - lenB; i++) {
curA = curA.next;
}
while (curA != null) {
if (curA == curB) return curA;
curA = curA.next;
curB = curB.next;
}
return null;
}
}
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode curA = headA;
ListNode curB = headB;
while (curA != curB) {
if (curA == null) curA = headB;
else curA = curA.next;
if (curB == null) curB = headA;
else curB = curB.next;
}
return curA;
}
}
此题结合图理解会清晰很多,双指针法的灵活运用。
时间复杂度:O(n + m)
空间复杂度:O(1)
代码随想录文章讲解:传送门
链接: 142. Linked List Cycle II
这一题的环形可以从上题得到一点启发,因为本题只有一个链表,如果把指针A和指针B都看作是在这个链表内行走,但是行走的步长不同,即快慢指针。同样结合图来理解会更容易。
这里用一下carl的图:
设快指针一次前进两个节点,慢指针一次前进一个节点。
当两个节点相遇时,快指针走过的路程为x+n(y+z)+y,慢指针走过的路程为x+y。这里可以这样理解,两个人赛跑,一个快一个慢,那当他们两个遇见的时候,肯定是慢的那个被套圈了。
将节点前进的步长看作速度,可以得到x+n(y+z)+y = 2(x+y),因为我们要得到环的入口,所以需要求x,得到x的表达式,由上可得,x=n(y+z)-y=(n-1)(y+z)+z,这意味着,当快慢指针相遇时,只要慢指针再走x步就能到达环形入口节点(不管是不是第一次到),而此时如果也有一个节点从头节点出发,每次也前进一个节点,那么它和慢节点会在环形入口节点相遇。
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast = head,slow = head;
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
if (fast == slow){
// 这里index2等于fast和slow都一样
// 因为它们此时相遇了,指向同一个节点
ListNode index1 = head, index2 = fast;
while(index1 != index2){
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}
return null;
}
}
对于查找倒数第几个节点、查找环入口、查找交点等链表问题,都要考虑用双指针法解决问题,以上几个题都是非常典型的链表中的双指针运用。解题过程可以多画图模拟,有助理解。
代码随想录文章讲解:传送门
代码随想录视频讲解:传送门