24.两两交换链表中的节点
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummyHead = new ListNode(0, head);
ListNode* cur = dummyHead; // 使用虚拟头节点,可以统一操作所有节点
ListNode* temp01;
ListNode* temp02;
// 注意事项:
// 此处的判断条件中,先判断当前节点的 next 是否为空,之后判断 当前节点的下一个节点的 next 是否为空
// 这样处理的原因是为了避免操作空指针引发异常
while (cur->next != nullptr && cur->next->next != nullptr) {
// 例如:链表为 dummyHead---> 1 ---> 2 ---> 3 --- > 4 ---> nullptr
temp01 = cur->next; // 保存数值为 1 的节点的地址
temp02 = cur->next->next->next; // 保存数值为 3 的节点的地址
cur->next = cur->next->next; // 将 dummyHead 指向数值为 2 的节点
cur->next->next = temp01; // 将数值为 2 的节点指向数值为 1 的节点
temp01->next = temp02; // 将数值为 1 的节点指向数值为 3 的节点
cur = cur->next->next; // cur 向右移动两个位置
}
return dummyHead->next; // 返回新链表的头节点
}
};
19.删除链表的倒数第 N 个节点
解法 1:
// a + b + c = b + c + a
// 若无交集,则 a + b = b + a
// 设交集长度为 c,去掉交集后短的长度为 a,长的长度为 b
// 则短链长度 a +c
// 则长链子长度 b +c
// b > a
// 第一轮可以让他们两个都移动 a + c 步
// 短链剩下长度 0
// 长链剩下长度 b - a
// 之后短链赋值为长链头节点
// 则之前的短链长度为 b + c
// 长链子长度为 b - a (长链子走到头会赋值短链提前说一下)
// 此时走 b 的长度
// 短链则为 b + c - b = c 正好是相交的头节点
// 长链子走 b 则为 b - a - b = -a 可知我们肯定是赋值了短链长度 a + c,又因为前面是 -a 故
// a + c - a = c 此时也是相交的头节点可以返回,代码实现如下,纯数学方法证明
// 思路:
// 两个指针分别从两个链表的头节点开始,遍历链表
// 当有其中一个链表为空时,将其指向另一个链表的头节点,否则指向本链表的下一个节点
// 不断循环,直到两个指针都为空时,说明两个链表没能相交
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* curA = headA; // 指向链表 A 的头节点
ListNode* curB = headB; // 指向链表 B 的头节点
while (curA != curB) { // 不断循环,直到两个指针都为空时,说明两个链表没有相交
if (curA == nullptr) { // 如果其中指针为空时,将其指向另一个链表的头节点
curA = headB;
} else {
curA = curA->next; // 否则指向本链表的下一个节点
}
if (curB == nullptr) { // 同理
curB = headA;
} else {
curB = curB->next;
}
}
// 此处返回 curA 与 curB 效果相同
return curA;
}
};
解法 2:
// 步骤:
// 1. 先计算出两个链表的长度
// 2. 计算出两个链表的长度差值
// 3. 较长链表先移动差值个节点
// 4. 两个链表从同位置的节点同时开始移动比较地址是否相同
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* curA = headA;
ListNode* curB = headB;
int lenA = 0;
int lenB = 0;
// 1. 计算两个链表的长度
while (curA != nullptr) {
curA = curA->next;
lenA++;
}
while (curB != nullptr) {
curB = curB->next;
lenB++;
}
// 2.计算出两个链表的差值
int distance = 0;
ListNode* fast = nullptr;
ListNode* slow = nullptr;
if (lenA > lenB) {
distance = lenA - lenB;
fast = headA;
slow = headB;
} else {
distance = lenB - lenA;
fast = headB;
slow = headA;
}
// 3.较长链表先移动差值个节点
while (distance > 0) {
distance--;
fast = fast->next;
}
// 4.两个链表从相同位置的节点开始同时移动,比较地址是否相同
while (fast != nullptr) {
if (fast == slow) {
return fast;
}
fast = fast->next;
slow = slow->next;
}
return nullptr; // 循环完毕,没有发现相交
}
};
142.环形链表II
// 思路:
// 首先判断是否存在环
// 之后找到环的入口
// 步骤:
// 1. 使用 fast 与 slow 指向链表的头节点
// 使 fast 一次移动两个节点的位置,slow 一次移动一个节点的位置,判断两个节点是否相交
// 2. 在相交处定义一个背后指针 index01,在链表头节点处定义一个指针 index02
// 使两个新指针从相交位置开始一次移动一个节点的位置,当再次相交的时,该位置就是环的入口
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
// 使用 fast 与 slow 指向两个链表的头节点
ListNode* fast = head;
ListNode* slow = head;
// 判断两个节点是否相交
// fast->next != nullptr 表明链表不存在环
while (fast != nullptr && fast->next != nullptr) {
fast = fast->next->next; // fast 一次移动两个节点的位置
slow = slow->next; // slow 一次移动一个节点的位置
// 是否存在环
if (fast == slow) {
ListNode* index01 = fast;
ListNode* index02 = head;
// 找出环的入口
while (index01 != index02) {
index01 = index01->next;
index02 = index02->next;
}
return index01;
}
}
return nullptr;
}
};