目录
前言
没提示会死,自己根本想不出来啊
LeetCode24.两两交换链表中的节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
思路
交换相邻两节点,需要操作连接它们的三个指针。
设置虚拟头节点。
第一次提交时没有考虑步骤一,导致链表出现分支。
完整代码
class Solution {
public ListNode swapPairs(ListNode head) {
if (head == null)
return null;
ListNode pre = new ListNode(0, head);
head = pre;
while (pre.next != null && pre.next.next != null) {
ListNode curr = pre.next;
ListNode next = pre.next.next;
curr.next = next.next; // 3
next.next = curr; // 2
pre.next = next; // 1
pre = curr;
}
return head.next;
}
}
LeetCode19.删除链表的倒数第N个节点
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
思路
快慢指针法:
设置虚拟头节点,初始快慢指针指向虚拟头节点。
先移动快指针n步,再同时移动快慢指针,当快指针遍历到末尾时,慢指针就指向了要删除的节点。
由于删除该节点要找到上一个节点,所以可以让快指针先走 n + 1 步。
此时快指针遍历到末尾时,慢指针恰好指向要删除节点的上一个。
执行删除操作。
编写代码时要注意判空,避免空指针异常。
完整代码
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummyNode = new ListNode(0, head);
ListNode slowIndex = dummyNode;
ListNode fastIndex = dummyNode;
while (n-- >= 0) {
fastIndex = fastIndex.next;
}
while (fastIndex != null) {
slowIndex = slowIndex.next;
fastIndex = fastIndex.next;
}
slowIndex.next = slowIndex.next.next;
return dummyNode.next;
}
}
LeetCode160.相交链表
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
思路
-
方法一:
求出两个链表的长度差,先移动长链表,对齐长度,然后一起移动。
比较指针直到相等。 -
方法二:
设A链表相交前的节点个数为 a ,A链表相交前的节点个数为 b ,共同节点个数为 c
A链表移动到末尾时跳转到B链表开始,A链表移动到末尾时跳转到B链表开始
同时移动 a + b + c + 1 步时,恰好为相交节点
如果没有相交部分,第 a + b + 1 步会同时为null,停止循环
所以移动条件判断的是currA而不是currA.next
currA.next不经过null位置,如果不相交就死循环了
注意:比较的是指针是否相等,即是否为同一个节点对象,而不是节点存储的值。
完整代码
public class Solution {
// 方法1
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode currA = headA;
ListNode currB = headB;
int lenA = 0;
int lenB = 0;
while (currA != null) {
lenA++;
currA = currA.next;
}
while (currB != null) {
lenB++;
currB = currB.next;
}
// 让currA保存较长链表的头节点
if (lenA >= lenB) {
currA = headA;
currB = headB;
} else {
currA = headB;
currB = headA;
}
// 长链表先移动的步数
int count = Math.abs(lenA - lenB);
while (count-- > 0) {
currA = currA.next;
}
while (currA != currB) {
currA = currA.next;
currB = currB.next;
}
return currA;
}
}
public class Solution {
// 方法2
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode currA = headA;
ListNode currB = headB;
while (currA != currB) {
// 移动A链表
if (currA != null) {
currA = currA.next;
} else {
currA = headB;
}
// 移动B链表
if (currB != null) {
currB = currB.next;
} else {
currB = headA;
}
}
return currA;
}
}
LeetCode142.环形链表Ⅱ
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
思路
这道题目,不仅考察对链表的操作,而且还需要一些数学运算。
主要考察两知识点:
- 判断链表是否环
- 如果有环,如何找到这个环的入口
- 快慢指针,快指针一次走2步,慢指针一次走1步。
如果有环会在环内相遇,因为进环就出不去了。
没有环快指针会先遍历到空节点。 - 设入环前距离为x,相遇位置距环入口距离为y,剩余环距离为z
可列方程,2 * (x + y) = x + n * (y + z) + y
化简得 x = (n - 1) * (y + z) + z
即从 相遇位置 和 起点 同时移动,会在环入口处相遇
完整代码
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
ListNode index1 = null;
ListNode index2 = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
index1 = slow;
break;
}
}
while (index1 != null && index1 != index2) {
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}
今日总结
完成比完美重要!完成比完美重要!完成比完美重要!
不要犯完美主义强迫症,虽然解法没写全,笔记总结了跟没总结一样。
下一章就离开舒适区了,一刷一定要坚持下来啊!