【C++】链表算法习题

🎆个人主页:夜晚中的人海

今日语录:不经历风雨,长不成大树,不受百炼,难以成钢。
文章目录
- ⭐一、两数相加
- 🏠二、两两交换链表中的节点
- 🚀三、重排链表
- 🏖️四、合并K个升序链表
- 🎄五、K个一组翻转链表
⭐一、两数相加
题目链接:两数相加
题目描述:

解题思路:
1.由题可知,两个链表都是逆序存储数字,因此它们对应的位置分别就是个位、十位等,直接相加即可
2.相加过程中,我们要注意是否会产生进位,如果产生进位,则再下一次运算时要加上进位(注: 如果在链表的最后一个位置产生进位,我们需要new一个结点用来存储最高位)
代码实现:
class Solution {
public:ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {ListNode* cur1 = l1,*cur2 = l2;//表示进位int t = 0;//创建头结点ListNode* newnode = new ListNode(0);ListNode* prev = newnode;while(cur1 || cur2 || t){if(cur1){t += cur1->val;cur1 = cur1->next;}if(cur2){t += cur2->val;cur2 = cur2->next;}prev->next = new ListNode(t % 10);prev = prev->next;t /= 10;}prev = newnode->next;delete newnode;return prev;}
};
🏠二、两两交换链表中的节点
题目链接:两两交换链表中的节点
题目描述:

解题思路:

代码实现:
class Solution {
public:ListNode* swapPairs(ListNode* head) {//判断链表为空情况if(head == nullptr || head->next == nullptr)return head;ListNode* newhead = new ListNode(0);newhead->next = head;ListNode* prev = newhead;ListNode* cur = prev->next,*next = cur->next,*nnext = next->next;while(cur && next){//头插链表prev->next = next;next->next = cur;cur->next = nnext;prev = cur;cur = nnext;if(cur)next = cur->next;if(next)nnext = next->next;} prev = newhead->next;delete newhead;return prev;}
};
🚀三、重排链表
题目链接:重排链表
题目描述:

解题思路:
1.先用快慢指针的方法找出中间节点
2.根据中间节点将链表断开,把中间节点之后的节点进行翻转
3.最后合并两个链表即可
代码实现:
class Solution {
public:void reorderList(ListNode* head) {if(head == nullptr || head->next == nullptr || head->next->next == nullptr)return;//用快慢指针找中间节点ListNode* slow = head,*fast = head;while(fast && fast->next){slow = slow->next;fast = fast->next->next;}ListNode* cur = slow->next;ListNode* newnode = new ListNode(0);slow->next = nullptr;//翻转链表while(cur){ListNode* next = cur->next;cur->next = newnode->next;newnode->next = cur;cur = next;}//合并两个有序链表ListNode* ret = new ListNode(0);ListNode* prev = ret;ListNode* cur1 = head,*cur2 = newnode->next;while(cur1){//存放第一个链表prev->next = cur1;cur1 = cur1->next;prev = prev->next;//存放第二个链表if(cur2){prev->next = cur2;cur2 = cur2->next;prev = prev->next;}}delete newnode;delete ret;}
};
🏖️四、合并K个升序链表
题目链接:合并K个升序链表
题目描述:

解题思路:
1.解法一:使用建堆算法。通过建一个小根堆,将所有的头结点都放入堆中,我们就能快速找到最小的那个结点
2.解法二:使用递归算法,将链表划分成两端,分别对左右两个链表进行递归,最终将这两个链表进行合并得到整个有序链表(归并算法的策略)
代码实现:
使用建堆算法:
class Solution {struct cmp{bool operator()(const ListNode* l1,const ListNode* l2){return l1->val > l2->val;}};
public:ListNode* mergeKLists(vector<ListNode*>& lists) {//创建一个小根堆priority_queue<ListNode*,vector<ListNode*>,cmp>heap;for(auto l : lists){if(l)heap.push(l);}//合并K个有序链表ListNode* newnode = new ListNode(0);ListNode* prev = newnode;while(!heap.empty()){ListNode* t = heap.top();heap.pop();prev->next = t;prev = t;if(t->next)heap.push(t->next);}prev = newnode->next;delete newnode;return prev;}
};
递归算法:
class Solution {
public:ListNode* mergeKLists(vector<ListNode*>& lists) {return merge(lists,0,lists.size() - 1);}ListNode* merge(vector<ListNode*>& lists,int left,int right){if(left > right)return nullptr;if(left == right)return lists[left];//划分区间int mid = (left + right) >> 1;ListNode* l1 = merge(lists,left,mid);ListNode* l2 = merge(lists,mid + 1,right);return mergelist(l1,l2);}ListNode* mergelist(ListNode* l1,ListNode* l2){if(l1 == nullptr)return l2;if(l2 == nullptr)return l1;ListNode* newhead = new ListNode(0);ListNode* prev = newhead;ListNode* cur1 = l1,*cur2 = l2;//合并两个有序链表while(cur1 && cur2){if(cur1->val <= cur2->val){prev->next = cur1;prev = cur1;cur1 = cur1->next;}else{prev->next = cur2;prev = cur2;cur2 = cur2->next;}}if(cur1)prev->next = cur1;if(cur2)prev->next = cur2;prev = newhead->next;delete newhead;return prev;}
};
🎄五、K个一组翻转链表
题目链接:K个一组翻转链表
题目描述:

解题思路:
1.先判断一共要逆序几组,可以使用链表中的总个数 n / k
2.使用两个for循环,外循环表示逆序的组数,内循环表示几个一组(注:在翻转之前先记录一下当前位置,方便我们后续找尾)
3.最后将不需要翻转的结点接上即可
代码实现:
class Solution {
public:ListNode* reverseKGroup(ListNode* head, int k) {//分组int n = 0;ListNode* cur = head;while(cur){cur = cur->next;n++;}n /= k;ListNode* newnode = new ListNode(0);newnode->next = head;cur = head;ListNode* prev = newnode;for(int i = 0;i < n;i++){//记录每组翻转后的尾结点ListNode* tmp = cur;for(int j = 0;j < k;j++){//头插节点,翻转链表ListNode* next = cur->next;cur->next = prev->next;prev->next = cur;cur = next;}prev = tmp;}//将不需要翻转的节点接上prev->next = cur;prev = newnode->next;delete newnode;return prev;}
};
今天的分享就到这里啦,希望对您有所帮助,感谢您的阅读!
