1. 两数相加
2. 两数相加https://leetcode.cn/problems/add-two-numbers/
https://leetcode.cn/problems/add-two-numbers/
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头
写法:迭代
cppclass Solution { public: ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { int carry=0,all=0; ListNode* phead=new ListNode(0);ListNode* cur=phead; while(l1&&l2) { all=l1->val+l2->val+carry; if(all>=10){carry=1;all%=10;} else{carry=0;} cur->next=new ListNode(all); cur=cur->next; l1=l1->next;l2=l2->next;all=0; } while(l1||l2) { if(l1){all=l1->val+carry; l1=l1->next;} if(l2){all=l2->val+carry; l2=l2->next;} if(all>=10){carry=1;all%=10;} else{carry=0;} cur->next=new ListNode(all);all=0; cur=cur->next; } if(carry==1) { cur->next=new ListNode(1); cur=cur->next; } cur=phead->next; delete phead; return cur; } };优化写法
cppclass Solution { public: ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { // 构造哑巴节点 dummy,最后返回 dummy.next, 以方便处理新链表的头节点。 ListNode* dummy = new ListNode(0); ListNode* node = dummy; // node 一直会变化(前进) int carrier = 0; // 进位 // 只要有没走到头的链表或者进位不为 0 就一直前进。 while (l1 || l2 || carrier) { // 求和,考虑可能有链表走到头 int sum = (l1 ? l1->val : 0) + (l2 ? l2->val : 0) + carrier; // 在尾部添加节点 node->next = new ListNode(sum % 10); node = node->next; // 更新进位,并向两个链表尾部前进 carrier = sum / 10; if (l1) l1 = l1->next; if (l2) l2 = l2->next; } ListNode* result = dummy->next; // 保存结果链表的头节点 delete dummy; // 释放哑节点的内存 return result; } };
2. 删除链表的倒数第N个节点
给你一个链表,删除链表的倒数第
n个结点,并且返回链表的头结点写法一:双指针
cppclass Solution { public: ListNode* removeNthFromEnd(ListNode* head, int n) { ListNode* cur=head;ListNode* prev=nullptr; int size=0; while(cur) {size++;cur=cur->next;} cur=head;int aim=size-n; while(aim--) { prev=cur; cur=cur->next; } if(cur==head) return head->next; if(head->next) prev->next=cur->next; else return nullptr; return head; } };
写法二:快慢指针
cppclass Solution { public: ListNode* removeNthFromEnd(ListNode* head, int n) { // 由于可能会删除链表头部,用哨兵节点简化代码 ListNode dummy{0, head}; ListNode* left = &dummy; ListNode* right = &dummy; while (n--) { right = right->next; // 右指针先向右走 n 步 } while (right->next) { left = left->next; right = right->next; // 左右指针一起走 } // 左指针的下一个节点就是倒数第 n 个节点 ListNode* nxt = left->next; left->next = left->next->next; delete nxt; return dummy.next; } };
3. 排序链表
148. 排序链表https://leetcode.cn/problems/sort-list/
https://leetcode.cn/problems/sort-list/
给你链表的头结点
head,请将其按 升序 排列并返回 排序后的链表写法一:STL
cppclass Solution { public: ListNode* sortList(ListNode* head) { multimap<int,ListNode*> hash; ListNode* cur=head; while(cur) { hash.insert({cur->val,cur}); cur=cur->next; } ListNode* phead=new ListNode(0);cur=phead; for(auto& e:hash) { cur->next=e.second; cur=cur->next; } cur->next=nullptr; return phead->next; } };
写法二:归并排序
cppclass Solution { public: ListNode* sortList(ListNode* head) { return mergeSort(head); } /** * 对给定的链表进行归并排序 */ ListNode* mergeSort(ListNode* head){ // 如果链表为空或只有一个节点,无需排序直接返回 if(!head || !head->next){ return head; } // 获取链表的中间节点,分别对左右子链表进行排序 ListNode* mid = getMid(head); ListNode* rightSorted = mergeSort(mid->next); // 排序右子链表 if(mid)mid->next = nullptr; // 断开两段子链表 ListNode* leftSorted = mergeSort(head); // 排序左子链表 return mergeTwoLists(leftSorted, rightSorted); // 两个子链表必然有序,合并两个有序的链表 } /** * 获取以head为头节点的链表中间节点 * 如果链表长度为奇数,返回最中间的那个节点 * 如果链表长度为偶数,返回中间靠左的那个节点 */ ListNode* getMid(ListNode* head){ if(!head)return head; ListNode* slow = head, *fast = head->next; // 快慢指针,慢指针初始为 while(fast != nullptr && fast->next != nullptr) { fast = fast->next->next; // 快指针每次移动两个节点 slow = slow->next; // 慢指针每次移动一个节点 } return slow; // 快指针到达链表尾部时,慢指针即指向中间节点 } /** * 合并两个有序链表list1和list2 */ ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) { ListNode* dummy = new ListNode(); // 伪头节点,用于定位合并链表的头节点 ListNode* node = dummy; // 新链表当前的最后一个节点,初始为伪头节点 // 直到两个链表都遍历完了,合并结束 while(list1 != nullptr || list2 != nullptr){ int val1 = list1 == nullptr ? 50001 : list1 -> val; // 如果链表1已经遍历完,val1取最大值,保证链表2的节点被选择到 int val2 = list2 == nullptr ? 50001 : list2 -> val; // 如果链表2已经遍历完,val2取最大值,保证链表1的节点被选择到 if(val1 < val2){ // 链表1的节点值更小,加入到合并链表,并更新链表1指向的节点 node -> next = list1; list1 = list1 -> next; }else{ // 链表2的节点值更小,加入到合并链表,并更新链表2指向的节点 node -> next = list2; list2 = list2 -> next; } node = node -> next; // 更新合并链表当前的最后一个节点指向 } return dummy -> next; // 伪头节点的下一个节点即为合并链表的头节点 } };
4. 重排链表
4LCR 026. 重排链表https://leetcode.cn/problems/LGjMqU/
https://leetcode.cn/problems/LGjMqU/
给定一个单链表
L的头节点head,单链表L表示为:
L0 → L1 → ... → Ln-1 → Ln
请将其重新排列后变为:
L0 → Ln → L1 → Ln-1 → L2 → Ln-2 → ...不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换
写法一:STL映射
cppclass Solution { public: void reorderList(ListNode* head) { if (!head->next) return; //处理边界 map<int,ListNode*> index;//记录位置 ListNode* cur=head;int i=0; while(cur) { index[i++]=cur; cur=cur->next; } i--;//保证索引正确 cur=head;int j=1;//前后挨个插入 while(j<=i) { cur->next=index[i--]; cur=cur->next; if(i!=j)//当i=j,只执行一次 {cur->next=index[j++]; cur=cur->next;} } cur->next=nullptr; } };写法二:反转+三指针**
**
cppclass Solution { public: void reorderList(ListNode* head) { ListNode* dummmy = new ListNode(0); dummmy->next = head; ListNode* slow = dummmy; ListNode* fast = dummmy; while (fast != nullptr && fast->next != nullptr) { slow = slow->next; fast = fast->next->next; } delete dummmy; dummmy = nullptr; ListNode* headB = slow->next; slow->next = nullptr; ListNode* p2 = reverseList(headB); ListNode* p1 = head; ListNode* p3 = nullptr; while (p2 != nullptr) { p3 = p1->next; p1->next = p2; p1 = p2; p2 = p3; } } ListNode* reverseList(ListNode* head) { if (head == nullptr) { return head; } ListNode* left = nullptr; ListNode* cur = head; ListNode* right = nullptr; while (cur != nullptr) { right = cur->next; cur->next = left; left = cur; cur = right; } return left; } };
5. 两两交换链表中的节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
写法一:迭代
cppclass Solution { public: ListNode* swapPairs(ListNode* head) { if(!head||!head->next) return head; ListNode* cur=head->next;ListNode* prev=head; //完成前两个 prev->next=cur->next; cur->next=head;head=cur; //后面再规律处理 cur=prev; prev=head;ListNode* prevv=nullptr; while(cur->next&&cur->next->next) { //规律移动 if(cur->next&&cur->next->next){ prevv=cur; cur=cur->next->next; prev=prev->next->next; } //交换流程 prev->next=cur->next; cur->next=prev; prevv->next=cur; //保持cur与prev的前后关系 cur=prev; prev=prevv->next; } //如果还剩下则为一个,不用交换 return head; } };写法二:递归
cppclass Solution { public: ListNode* swapPairs(ListNode* head) { if (head == nullptr || head->next == nullptr) { return head; } ListNode* node1 = head; ListNode* node2 = head->next; ListNode* node3 = node2->next; node1->next = swapPairs(node3); // 1 指向递归返回的链表头 node2->next = node1; // 2 指向 1 return node2; // 返回交换后的链表头节点 } };
6. 合并K个升序链表
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
写法一:STL映射
cppclass Solution { public: ListNode* mergeKLists(vector<ListNode*>& lists) { if(lists.size()==0)return nullptr; if(lists.size()==1)return lists[0]; //用哈希记录索引和节点地址 multimap<int,ListNode*> nodemap; for(auto& e:lists) { ListNode* cur=e; while(cur) { nodemap.insert({cur->val,cur}); cur=cur->next; } } //重组链表 ListNode* phead=new ListNode(0);ListNode* cur=phead; for(auto& e:nodemap) { cur->next=e.second; cur=cur->next; } cur->next=nullptr; return phead->next; } };写法二:优先级队列(⭐⭐)
cppclass Solution { public: ListNode* mergeKLists(vector<ListNode*>& lists) { auto cmp = [](const ListNode* a, const ListNode* b) { return a->val > b->val; // 最小堆 }; priority_queue<ListNode*, vector<ListNode*>, decltype(cmp)> pq; for (auto head : lists) { if (head) { pq.push(head); // 把所有非空链表的头节点入堆 } } ListNode dummy{}; // 哨兵节点,作为合并后链表头节点的前一个节点 auto cur = &dummy; while (!pq.empty()) { // 循环直到堆为空 auto node = pq.top(); // 剩余节点中的最小节点 pq.pop(); if (node->next) { // 下一个节点不为空 pq.push(node->next); // 下一个节点有可能是最小节点,入堆 } cur->next = node; // 把 node 添加到新链表的末尾 cur = cur->next; // 准备合并下一个节点 } return dummy.next; // 哨兵节点的下一个节点就是新链表的头节点 } };非常重要!
7. K个一组翻转链表
给你链表的头节点
head,每k个节点一组进行翻转,请你返回修改后的链表。
k是一个正整数,它的值小于或等于链表的长度。如果节点总数不是k的整数倍,那么请将最后剩余的节点保持原有顺序。你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
写法一:栈
cppclass Solution { public: ListNode* reverseKGroup(ListNode* head, int k) { if (k <= 1) return head; stack<ListNode*> st; ListNode* phead=new ListNode(0);ListNode* pcur=phead; ListNode* cur=head; //统计节点数量 int size=0; while(cur){cur=cur->next;size++;} //按k的数量依次处理 int n=0,count=0;cur=head; while(count+k<=size) { while(n<k&&cur) { st.push(cur); cur=cur->next; n++;count++; } while(!st.empty()) { pcur->next=st.top(); st.pop(); pcur=pcur->next; } n=0; } //处理末尾情况 if(count<size) pcur->next=cur; else pcur->next=nullptr; cur=phead->next; delete phead; return cur; } };
写法二:递归
cppclass Solution { public: ListNode* reverseKGroup(ListNode* head, int k) { ListNode *p = head; for(int i = 0; i < k; i++) { if(!p) return head; p = p->next; } ListNode *q = head; ListNode *pre = nullptr; while(q != p) { ListNode *tmp = q->next; q->next = pre; pre = q; q = tmp; } head->next = reverseKGroup(p, k); return pre; } };

**

