24 两两交换链表中的节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)
解题思维:
对于移动链表节点的问题,主要两个两种解法:
- 虚拟头结点法
- 递归法
public ListNode swap(ListNode head) {
if (head == null || head.next == null) return head;
ListNode dummyNode = new ListNode(0);
dummyNode.next = head;
ListNode prev = dummyNode;
while (prev.next != null && prev.next.next != null) {
ListNode temp = head.next.next;
prev.next = head.next;
head.next.next = head;
head.next = temp;
prev = head;
head = head.next;
}
return dummyNode.next;
}
public ListNode swapPairs(ListNode head) {
if (head == null || head.next == null) return head;
ListNode next = head.next;
// 递归下两个
ListNode listNode = swapPairs(next.next);
// 交换数据
next.next = head;
head.next = listNode;
return head;
}
19 删除链表的倒数第 N 个结点
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
解题思路:
- 暴力解法:首先取出链表的头结点,然后通过head.next来遍历整个链表的个数,然后再次遍历链表取出倒数第n个结点
- 快慢指针法:首先快指针先走n步数,然后快慢指针同时走,当快指针为null的时候,慢指针就是指向的倒数第N个结点
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummyNode = new ListNode();
dummyNode.next = head;
ListNode fastIndex = dummyNode;
ListNode slowIndex = dummyNode;
// 快指针先走n个节点
for (int i = 0; i < n; i++) {
fastIndex = fastIndex.next;
}
while (fastIndex.next != null) {
fastIndex = fastIndex.next;
slowIndex = slowIndex.next;
}
// 删除第n个节点
slowIndex.next = slowIndex.next.next;
return dummyNode.next;
}
07 链表相交
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
解题思路:题目隐藏的一个点:如果
listA和listB有交点,intersectVal == listA[skipA + 1] == listB[skipB + 1]这个是重点:
- 求出两个链表A、B的长度、长度差gap,保证A为最长的链表
- A链表先走gap,然后A、B链表同时向后移动,如果相等则返回,否者返回null
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode curA = headA;
ListNode curB = headB;
int lenA = 0, lenB = 0;
while (curA != null) { // 求链表A的长度
lenA++;
curA = curA.next;
}
while (curB != null) {
lenB++;
curB = curB.next;
}
curA = headA;
curB = headB;
// 让curA为最长链表的头,leaA为其长度 (此时保证A链表为最长的链表)
if (lenB > lenA) {
int tempLen = lenA;
lenA = lenB;
lenB = tempLen;
ListNode tempNode = curA;
curA = curB;
curB = tempNode;
}
// 求长度差
int gap = lenA - lenB;
// A链表移动长度差
while (gap-- > 0) {
curA = curA.next;
}
while (curA != null) {
if (curA == curB) {
return curA;
}
curA = curA.next;
curB = curB.next;
}
return null;
}
142. 环形链表 II
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
解题思路:
- 此题重要的是需要一个移动一个位置的慢指针,一个移动2个位置的快指针。同时向前移动,如果有环必定相遇。
- 当两人相等有环时候,这个时候需要特殊处理,同时向前移动,一个点从头开始,一个点从相遇点开始移动,再次相等则为环入口
public ListNode detectCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) { // 有环
ListNode index1 = fast;
ListNode index2 = head;
// 两个指针,从头节点和相遇结点,各走一步,直到连个节点相等,相遇点为环入口 // 这个是2(x+y) = x+y+n(y+z) 当n=1成立的点,一个点从相遇点开始、一个点从头开始
while (index1 != index2) {
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}
return null;
}