本次题目
- 19 删除链表的倒数第N个节点
- 面试题02.07 链表相交
- 142 环形链表II
19 删除链表的倒数第N个节点
- 建议使用虚拟头结点,方便处理删除头结点的情况。
- 双指针:快指针比慢指针快N+1个节点,当快指针指向链表末尾时慢指针指向倒数第N+1个节点,方便删除第N个节点(删除慢指针指向的下一个节点)。
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode virtualHead = new ListNode(0);
virtualHead.next = head;
ListNode fast = virtualHead;
ListNode slow = virtualHead;
for(int i = 0; i <= n; i++){
fast = fast.next;
}
while(fast != null){
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return virtualHead.next;
}
}
面试题02.07 链表相交
- 求两个链表交点节点的指针,交点是指针相等而不是数值相等,从交点开始直到末尾的节点数值都相同,因此可以将两个链表的末尾对齐,指针指向较短链表的头结点开始向链表末尾前进遍历。
- 注意:判断两个链表谁长谁短,可以通过始终设置链表A为较长链表从而减少代码重复。
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode curA = headA;
ListNode curB = headB;
int lenA = 0;
int lenB = 0;
while(curA != null){
lenA++;
curA = curA.next;
}
while(curB != null){
lenB++;
curB = curB.next;
}
curA = headA;
curB = headB;
if(lenA > lenB){
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;
}
}else{
for(int i = 0; i < lenB-lenA; i++){
curB = curB.next;
}
while(curA != null){
if(curA == curB){
return curA;
}
curA = curA.next;
curB = curB.next;
}
}
return null;
}
}
142 环形链表II
- 判断链表是否有环:双指针(快慢指针),快慢指针先后从头结点出发,快指针每次移动两个节点,慢指针每次移动一个节点,若快慢指针相遇,则链表有环(快追慢)。注意:链表长度不能小于2。
- 判断环的入口:数学分析,设从快慢指针相遇节点出发到环入口节点的长度z,从头结点出发到环入口节点的长度x,从环入口节点到快慢指针相遇节点的长度为y,由慢指针走过的点数 * 2 = 快指针走过的点数,得到(x+y)2=x+y+n(y+z),即x=(n-1)(y+z)+z,其中,n为大于等于1的整数,(y+z)为环的长度。因此,两个指针分别从头结点和快慢指针相遇位置出发,每次移动一个节点,相遇的位置就是环入口节点
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 = fast;
ListNode index2 = head;
while(index1 != index2){
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}
return null;
}
}