链表高频题
160. 相交链表
#include <vector>
#include <iostream>
#include <algorithm>
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
if (headA == nullptr || headB == nullptr) return nullptr;
ListNode *a = headA;
ListNode *b = headB;
int diff = 0;
while (a->next != nullptr) {
a = a->next;
diff++;
}
while (b->next != nullptr) {
b = b->next;
diff--;
}
// 根本就不重合
if (a != b) return nullptr;
// 较长的链表赋给 a
if (diff > 0) {
a = headA;
b = headB;
} else {
a = headB;
b = headA;
}
diff = abs(diff);
// 较长的链表先走 diff 步
while (diff-- != 0)
a = a->next;
// 距离尾节点距离相同时,同时出发
while (a != b) {
a = a->next;
b = b->next;
}
return a;
}
};
25. K 个一组翻转链表
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
struct ListNode {
int val;
ListNode *next;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode *next) : val(x), next(next) {}
};
class Solution {
public:
ListNode *reverseList(ListNode *head, ListNode *tail) {
ListNode *pre = tail->next, *cur = head, *next;
ListNode *nextNode = tail->next;
while (cur != nullptr && cur != nextNode) {
next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
ListNode *reverseKGroup(ListNode *head, int k) {
// 虚拟头节点,接在链表最前面,使得第一段要反转的链表部分的处理和后面统一
ListNode *dummyHead = new ListNode(0, head);
ListNode *pre = dummyHead;
ListNode *left = dummyHead;
ListNode *right;
// 后移次数
int count;
while (pre->next != nullptr) {
// left、right 移到下一段要反转的链表的头部
left = pre->next;
right = left;
// right 后移 k-1 个节点
for (count = k - 1; count != 0 && right->next != nullptr; count--)
right = right->next;
// 链表元素总数小于 k
if (count != 0) return dummyHead->next;
// 把反转后的部分接到前面的链表上
pre->next = reverseList(left, right);
// 反转后 left 节点变成反转部分的尾节点,也就是下一段要反转的部分的上一个节点
pre = left;
}
return dummyHead->next;
}
};
138. 随机链表的复制
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
class Node {
public:
int val;
Node *next;
Node *random;
Node(int _val) {
val = _val;
next = nullptr;
random = nullptr;
}
};
class Solution {
public:
Node *copyRandomList(Node *head) {
if (head == nullptr) return nullptr;
Node *pre = head;
// 遍历原链表,在每个节点后面插入新节点
while (pre != nullptr) {
// 复制原节点的值
Node *node = new Node(pre->val);
// 接在原节点的后面
node->next = pre->next;
pre->next = node;
pre = pre->next->next;
}
pre = head;
// 遍历链表,复制 random 指针
while (pre != nullptr) {
if (pre->random != nullptr)
pre->next->random = pre->random->next;
pre = pre->next->next;
}
pre = head;
Node *res = head->next;
Node *cur = head->next;
// 分离出复制出的链表
while (cur != nullptr && cur->next != nullptr) {
// 改回原链表节点的 next 指针
pre->next = pre->next->next;
pre = pre->next;
// 新链表的节点从原链表中分离出来,串在一起
cur->next = cur->next->next;
cur = cur->next;
}
// 原链表尾节点的 next 指针
pre->next = nullptr;
return res;
}
};
234. 回文链表
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
struct ListNode {
int val;
ListNode *next;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode *next) : val(x), next(next) {}
};
class Solution {
public:
// 返回向上取整的中间节点
// [1, 2, 3, 4] 返回 3
ListNode *findMid(ListNode *head) {
ListNode *slow = head;
ListNode *fast = head;
while (fast != nullptr && fast->next != nullptr) {
fast = fast->next->next;
slow = slow->next;
}
return slow;
}
// 原地反转
ListNode *reverseList(ListNode *head) {
ListNode *pre = nullptr;
ListNode *cur = head;
ListNode *next;
while (cur != nullptr) {
next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
bool isPalindrome(ListNode *head) {
ListNode *mid = findMid(head);
mid = reverseList(mid);
ListNode *p = head;
ListNode *q = mid;
while (q != nullptr) {
if (p->val != q->val) return false;
p = p->next;
q = q->next;
}
return true;
}
};
142. 环形链表 II
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(nullptr) {}
};
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
// 环外节点数 a,环内节点数 b
// 快慢指针经过的节点个数关系: f = 2s
// 相遇时: f = s + n*b -> s = n*b, f = 2*n*b
// 走到入口节点经过的节点个数 k = a + n*b, 先前进 a 步到入口节点, 然后在环里转圈
// f = 0, s = n*b -> f = a, s = a + n*b 相遇在入口节点
ListNode *slow = head, *fast = head;
while (fast != nullptr && fast->next != nullptr) {
slow = slow->next;
fast = fast->next->next;
// 首次相遇时,slow 已经跑了 b 步,只需跑 a 步就能到达入口
// fast 返回开头 head 节点,也只需跑 a 步就能到达入口
// 此时 a 是几并不知道,但是可以确定的是,slow 和fast 都在跑 a 步就会在入口相遇
if (slow == fast) {
fast = head;
// 此时 f = 0, s = 1*b
while (slow != fast) {
slow = slow->next;
fast = fast->next;
}
// 结束时 f = a, s = a + 1*b
return slow;
}
}
return nullptr;
}
};
148. 排序链表
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
struct ListNode {
int val;
ListNode *next;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode *next) : val(x), next(next) {}
};
class Solution {
public:
// 链表归并
ListNode *merge(ListNode *l1, ListNode *l2) {
if (l1 == nullptr || l2 == nullptr) return l1 == nullptr ? l2 : l1;
ListNode *dummyHead = new ListNode();
ListNode *pre = dummyHead;
while (l1 != nullptr && l2 != nullptr) {
if (l1->val < l2->val) {
pre->next = l1;
l1 = l1->next;
} else {
pre->next = l2;
l2 = l2->next;
}
pre = pre->next;
}
if (l1 != nullptr) pre->next = l1;
if (l2 != nullptr) pre->next = l2;
return dummyHead->next;
}
// 时间复杂度 O(n * logn),额外空间复杂度 O(1),稳定
ListNode *sortList(ListNode *head) {
// 统计链表长
int len = 0;
ListNode *temp = head;
while (temp != nullptr) {
len++;
temp = temp->next;
}
ListNode *dummyHead = new ListNode();
dummyHead->next = head;
// 步长每次乘二
for (int gap = 1; gap < len; gap <<= 1) {
ListNode *pre = dummyHead;
ListNode *cur = dummyHead->next;
// 每次从一组元素的首个元素节点开始(两个子链表为一组)
while (cur != nullptr) {
// 长度为 gap 的子链表 l1
ListNode *l1 = cur;
int i = 1;
while (i < gap && cur->next != nullptr) {
cur = cur->next;
i++;
}
// 子链表 l2
ListNode *l2 = cur->next;
// 把 l2 从 l1 后面断开
cur->next = nullptr;
// 找到子链表 l2 的末尾,l2 可能是最后一个子链表并且长度小于等于 gap
// l2 后面可能还有
cur = l2;
i = 1;
while (i < gap && cur != nullptr && cur->next != nullptr) {
cur = cur->next;
i++;
}
ListNode *next = nullptr;
// l2 后面还有节点时
if (cur != nullptr) {
// 下一组的起点(两个子链表为一组)
next = cur->next;
// 断开,l2变成完成的一条链表
cur->next = nullptr;
}
// 把这组的两个子链表合并
pre->next = merge(l1, l2);
// pre 移到合并后的最后一个节点,等待接上下一组合并后的首个节点
while (pre->next != nullptr)
pre = pre->next;
// 进入下一组的归并
cur = next;
}
}
return dummyHead->next;
}
};
标签:pre,ListNode,cur,nullptr,next,链表,高频
From: https://www.cnblogs.com/sprinining/p/18438640