个人博客主页:http://myblog.nxx.nx.cn
代码GitHub地址:https://github.com/nx-xn2002/Data_Structure.git
Day4
24. 两两交换链表中的节点
题目链接:
https://leetcode.cn/problems/swap-nodes-in-pairs/
题目描述:
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
思路:
对于这道题,我的思路类似于前一天的反转链表的一种做法,也就是使用递归。将前两个节点交换位置后,递归调用第三个节点,将结果作为第三个节点。
/**
* 递归实现
*/
public ListNode swapPairs(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode newHead = head.next;
head.next = swapPairs(newHead.next);
newHead.next = head;
return newHead;
}
19. 删除链表的倒数第 N 个结点
题目链接:
https://leetcode.cn/problems/remove-nth-node-from-end-of-list/
题目描述:
给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
思路:
本题的最简单的思路就是先遍历定位到倒数第 n 个节点,然后在第二次遍历中进行删除。但这样使用了两次遍历,还有更巧妙的方法只需要一次遍历就能解决,也就是快慢指针。
已知倒数第 n 个节点其实就是最后一个节点往前推 n 个节点,那么遍历的时候,我们一开始可以使用两个指针,一个指针先于另一个指针 n 个节点到达链表结尾,此时慢的那个指针的位置就是我们找的位置。
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) {
return null;
}
ListNode a = headA, b = headB;
int count = 0;
while (a != b) {
if (count > 2) {
return null;
}
if (a.next == null) {
a = headB;
count++;
} else {
a = a.next;
}
if (b.next == null) {
b = headA;
count++;
} else {
b = b.next;
}
}
return a;
}
面试题 02.07. 链表相交
题目链接:
https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/
题目描述:
给你两个单链表的头节点 headA
和 headB
,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null
。
思路:
本题的一个重点在于,节点的数值相同不代表节点相同,应该是节点的地址相同,这一点在 Java 中可以直接用 ==
进行判断。这道题的思路就是无论是否有环,尝试让两个指针将两个链表都遍历一次,如果路途中相遇了,说明有环。
public ListNode detectCycle(ListNode head) {
ListNode fast = head, slow = head;
while (true) {
if (fast == null || fast.next == null) {
return null;
}
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
break;
}
}
fast = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return fast;
}
面试题 02.07. 链表相交
题目链接:
https://leetcode.cn/problems/linked-list-cycle-ii/
题目描述:
给定一个链表的头节点 head
,返回链表开始入环的第一个节点。 如果链表无环,则返回 null
。
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0
开始)。如果 pos
是 -1
,则在该链表中没有环。注意:pos
不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改链表。
思路:
这道题也是用追及的思路,使用快慢指针,快指针一次走两步,慢指针一次走一步,因此在存在环的情况下,相当于快指针每次追一步,两个指针会在环的入口处相遇。
public ListNode detectCycle(ListNode head) {
ListNode fast = head, slow = head;
while (true) {
if (fast == null || fast.next == null) {
return null;
}
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
break;
}
}
fast = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return fast;
}