链表类题目之CPP版
🚀 反转链表
ListNode* ReverseList(ListNode* head) {
// write code here 双指针
ListNode* pre = nullptr;
ListNode* cur = head;
while(cur != nullptr){
auto tmp = cur->next;
cur->next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
🚀 链表内指定区间反转
ListNode* reverseBetween(ListNode* head, int m, int n) {
// write code here
ListNode* dummpy = new ListNode(-1);
dummpy->next = head;
ListNode* pre = dummpy;
for(int i = 0; i < m - 1; i++){
pre = pre->next;
}
ListNode* cur = pre->next;
for(int i = 0; i < n - m; i++){
auto tmp = cur->next;
cur->next = cur->next->next;
// 顺序不能改变
tmp->next = pre->next;
pre->next = tmp;
}
return dummpy->next;
}
🚀 合并两个排序的链表
ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
// write code here
ListNode* dummpy = new ListNode(-1);
ListNode* cur = dummpy;
while(pHead1 != nullptr && pHead2 != nullptr){
if(pHead1->val <= pHead2->val){
cur->next = pHead1;
pHead1 = pHead1->next;
}else{
cur->next = pHead2;
pHead2 = pHead2->next;
}
cur = cur->next;
}
if(pHead1 != nullptr) cur->next = pHead1;
if(pHead2 != nullptr) cur->next = pHead2;
return dummpy->next;
}
🚀 合并k个已排序的链表
-
c++优先队列
priority_queue
(自定义比较函数)通过struct
重载()
操作符struct cmp{ bool operator()(ListNode* a, ListNode* b){ return a->val > b->val; // 完成greater功能 } };
-
通过优先级队列实现
struct cmp{ bool operator()(ListNode* a, ListNode* b){ return a->val > b->val; } }; ListNode* mergeKLists(vector<ListNode*>& lists) { // write code here priority_queue<ListNode*, vector<ListNode*>, cmp> heap; ListNode* dummpy = new ListNode(-1); for(auto node: lists){ if(node != nullptr){ heap.push(node); } } ListNode* cur = dummpy; while(!heap.empty()){ auto tmp = heap.top(); heap.pop(); //取出堆顶元素并弹出 cur->next = tmp; cur = cur->next; if(tmp->next != nullptr){ heap.push(tmp->next); } } return dummpy->next; }
🚀 判断链表中是否有环
class Solution {
public:
// 双指针
bool hasCycle(ListNode *head) {
ListNode* low = head;
ListNode* fast = head;
while(fast != nullptr && fast->next != nullptr){
fast = fast->next->next;
low = low->next;
if(fast == low){
return true;
}
}
return false;
}
};
🚀 链表中环的入口节点
关键在于:入口节点到头节点的距离 = N*相遇点到入口节点的距离. 视频解析
ListNode* EntryNodeOfLoop(ListNode* pHead) {
ListNode* fast = pHead;
ListNode* low = pHead;
while(fast != nullptr && fast->next != nullptr){
fast = fast->next->next;
low = low->next;
if(fast == low){
break;
}
}
if(fast == nullptr || fast->next == nullptr) return nullptr;
fast = pHead;
while(fast != low){
fast = fast->next;
low = low->next;
}
return low;
}
🚀 链表中倒数第k个节点
- 双指针:让
fast
指针先走k步,然后fast
和low
齐头并进,当fast
指针走到nullptr
时,low
指针即为倒数第k个节点 - 需要注意k的合法性,比如k大于链表的长度
ListNode* FindKthToTail(ListNode* pHead, int k) {
// write code here 双指针
ListNode* fast = pHead;
ListNode* low = pHead;
for(int i = 0; i < k; i++){
if(fast != nullptr){ //判断fast是否为nullptr
fast = fast->next;
}else{
return nullptr;
}
}
while(fast != nullptr){
fast = fast->next;
low = low->next;
}
return low;
}
🚀 两个链表的第一个公共节点
-
双指针:每个指针遍历一个链表,当其中一个指针遍历到
nullptr
时,则重新指向另一个链表的头节点。当两个指针相遇时即为第一个公共头节点。 -
需要注意当其中一个链表为空时,直接返回
nullptr
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) { if(pHead1 == nullptr || pHead2 == nullptr) return nullptr; //双指针 ListNode* p1 = pHead1; ListNode* p2 = pHead2; while(p1 != nullptr || p2 != nullptr){ if(p1 == nullptr) p1 = pHead2; if(p2 == nullptr) p2 = pHead1; if(p1 == p2) return p1; p1 = p1->next; p2 = p2->next; } return nullptr; }
🚀 链表相加
-
反转链表,逐节点相加,当两个节点都为空且进位为空时,循环结束。
ListNode* addInList(ListNode* head1, ListNode* head2) { // write code here ListNode* p1 = reverseList(head1); ListNode* p2 = reverseList(head2); // 结果链表 ListNode* dummpy = new ListNode(-1); ListNode* pre = dummpy; ListNode* cur = nullptr; int carry = 0; while(p1 != nullptr || p2 != nullptr || carry != 0){ int val1 = p1 == nullptr ? 0: p1->val; int val2 = p2 == nullptr ? 0: p2->val; int sum = val1 + val2 + carry; cur = new ListNode(sum%10); pre->next = cur; pre = pre->next; carry = sum / 10; if(p1 != nullptr) p1 = p1->next; if(p2 != nullptr) p2 = p2->next; } return reverseList(dummpy->next); } ListNode* reverseList(ListNode* head){ ListNode* pre = nullptr; ListNode* cur = head; while(cur != nullptr){ auto tmp = cur->next; cur->next = pre; pre = cur; cur = tmp; } return pre; }
🚀 单链表排序
- 向下归并排序 视频解析
class Solution {
public:
ListNode* sortInList(ListNode* head) {
// 统计链表长度
int length(0);
for(ListNode* node=head; node != nullptr; node=node->next) length++;
// 循环O(logN)次
for(int i = 1; i < length; i *= 2){
// 初始化结果链表
ListNode* dummpy = new ListNode(-1), *cur = dummpy;
int cnt = ceil(1.0*length/(2.0*i));
// 依次排序
while(cnt--){
ListNode* p = head, *q = head;
for(int j = 0; j < i && q; j++) q = q->next;
// 记录下一次排序的起始位置
ListNode* next = q;
for(int j = 0; j < i && next; j++) next = next->next;
// 归并排序
int l = 0, r = 0;
while(l < i && r < i && p && q){
if(p->val <= q->val) cur = cur->next = p, p = p->next, l++;
else cur = cur ->next = q, q = q->next, r++;
}
// 扫尾
while(l < i && p) cur = cur->next = p, p = p->next, l++;
while(r < i && q) cur = cur ->next = q, q = q->next, r++;
head = next;
}
cur->next = nullptr;
head = dummpy->next;
}
return head;
}
};
🚀 判断一个链表是否回文
-
快慢指针找到中点,然后反转后半部分链表,最后一一对比即可
bool isPail(ListNode* head) { // 找到链表的中点 ListNode* fast = head, *low = head; while(fast != nullptr && fast->next != nullptr){ fast = fast->next->next; low = low->next; } low = reverseList(low); fast = head; // 一一对比 while(fast != nullptr && low != nullptr){ if(fast->val != low->val) return false; fast = fast->next; low = low->next; } return true; } ListNode* reverseList(ListNode* head){ ListNode* pre = nullptr; ListNode* cur = head; while(cur){ auto temp = cur->next; cur->next = pre; pre = cur; cur = temp; } return pre; }
🚀 链表的奇偶重排
ListNode* oddEvenList(ListNode* head) {
// write code here
if(head == nullptr || head->next == nullptr) return head;
ListNode* pre = head;
ListNode* cur = head->next;
ListNode* curHead = head->next;
while(cur != nullptr && cur->next != nullptr){
// 交叉连接
pre->next = cur->next;
pre = pre->next;
cur->next = pre->next;
cur = cur->next;
}
pre->next = curHead;
return head;
}
🚀 删除有序链表中的重复元素
ListNode* deleteDuplicates(ListNode* head) {
// write code here
ListNode* low = head, *fast = head;
while(fast != nullptr){
while(fast != nullptr && low->val == fast->val) fast = fast->next;
low->next = fast;
low = fast;
}
return head;
}
🚀 删除有序链表中的重复元素Ⅱ
ListNode* deleteDuplicates(ListNode* head) {
// write code here
// 头节点可能会被删除, 新建一个虚拟头节点
ListNode* dummpy = new ListNode(-1);
dummpy->next = head;
ListNode* pre = dummpy;
while(pre->next != nullptr){
auto cur = pre->next;
while(cur != nullptr && pre->next->val == cur->val) cur = cur->next;
if(pre->next->next == cur) pre = pre->next;
else pre->next = cur;
}
return dummpy->next;
}
😸点赞是最大的鼓励😸