24. 两两交换链表中的节点
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
主要考察对链表的复杂操作,难度不大
class Solution {
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null) return head;
ListNode dummy = new ListNode(-1 ,head);
ListNode front = head.next;
ListNode mid = head;
ListNode tail = dummy;
while (front != null){
ListNode temp = front.next;
tail.next = front;
front.next = mid;
mid.next = temp;
tail = mid;
mid = temp;
if (mid == null) break;
front =mid.next;
}
return dummy.next;
}
}
19.删除链表的倒数第N个节点
使用双指针,两者间距n个节点,则当快的指针到达末尾后,慢指针刚好指向倒数第N个节点,由于是删除操作,使用前驱节点来进行查找
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(-1, head);
ListNode pre = dummy;
ListNode fast = head;
for (int i = 0; i < n; i++) {
fast = fast.next;
}
while (fast != null){
fast = fast.next;
pre = pre.next;
}
pre.next = pre.next.next;
return dummy.next;
}
}
面试题 02.07. 链表相交
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
图示两个链表在节点 c1 开始相交:
比较容易想到,将长链表的队头指针先向后移动两条链表的差值个节点,则此时若AB存在交点,则两个队头指针到交点的距离相同,此时只要将两个链表头指针同时向后移动,找到相同的节点之后返回即可,若不存在交点,则两指针同时为空时都为null,符合题目要求
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode dummyA = new ListNode(-1, headA);
ListNode dummyB= new ListNode(-1, headB);
int count = 1;
while (headA != null){
count++;
headA = headA.next;
}
while (headB != null){
count--;
headB = headB.next;
}
headA = dummyA.next;
headB = dummyB.next;
if (count < 1){
count = 1 - count;
while (count-- != 0){
headB = headB.next;
}
}else {
while (count-- != 1){
headA = headA.next;
}
}
while (headA != headB){
headA = headA.next;
headB = headB.next;
}
return headA;
}
}
142.环形链表II
题意: 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
思路:这题首先需要解决的是判断链表是否为环。解决链表题目时,多指针是我们常会选用的方法,双指针法能否解决本题,我们先思考。
当两个指针都进入到环形区域后,继续向后遍历,指针会一直在链表里“绕圈”。而如果两个指针的速度,即前进的步长不同,最终一定会出现一个指针追上另一个指针的情况,追上时可能两个指针恰好重合,也可能快指针直接超过了慢指针。超过的情况是我们不喜欢的,因为不好判断。我们喜欢刚好重合,一旦重合,就可以确定链表为环形,因为快指针追上了慢的指针。
这个时候两个指针在环形区域的情况就简化成了追击问题,快指针速度每比慢指针速度多一,则每次移动时,快指针和慢指针的距离减一,那快指针的速度只要比慢指针速度刚好多一,则可以保证在追击时,快指针一定会和慢指针重合(移动一次距离减一),一定可以将距离减为0,即重合。好了,判断是否为环的问题就完全解决了。接下来看看如何找到入环节点。
图中标出了三个点,链表头节点,入环节点,相遇节点。我们很容易可以得出,相遇时:
慢指针走过了:a1+a2
快指针走过了:a1 + a2 + a3 + a2
因为慢指针速度为1,快指针速度为2,所以有
2x(a1+a2) = a1 + a2 + a3 + a2
解得a1 = a3
由于a1长度等于a3,所以此时如果我们将一个节点从相遇节点向后遍历,一个节点从头节点向后遍历,则相遇点即为入环点
public class Solution {
public ListNode detectCycle(ListNode head) {
if (head == null || head.next == null) return null;
ListNode fast = head;
ListNode slow = head;
while (fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
break;
}
}
if (fast == null || slow != fast) {
return null;
}
fast = head;
while (fast != slow) {
fast = fast.next;
slow = slow.next;
}
return fast;
}
}