链表高频题
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;// 较长的链表赋给 aif (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;// 链表元素总数小于 kif (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] 返回 3ListNode *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*bwhile (slow != fast) {slow = slow->next;fast = fast->next;}// 结束时 f = a, s = a + 1*breturn 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 的子链表 l1ListNode *l1 = cur;int i = 1;while (i < gap && cur->next != nullptr) {cur = cur->next;i++;}// 子链表 l2ListNode *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;}
};