免费的网站建设一般多少钱,河北秦皇岛黄金海岸,如何部署php网站,织梦小说网站源码目录
①力扣2. 两数相加
解析代码
②力扣24. 两两交换链表中的节点
解析代码
③力扣143. 重排链表
解析代码
④力扣23. 合并 K 个升序链表
解析代码1#xff08;小根堆优化#xff09;
解析代码2#xff08;递归_归并#xff09;
⑤力扣25. K 个一组翻转链表
解…目录
①力扣2. 两数相加
解析代码
②力扣24. 两两交换链表中的节点
解析代码
③力扣143. 重排链表
解析代码
④力扣23. 合并 K 个升序链表
解析代码1小根堆优化
解析代码2递归_归并
⑤力扣25. K 个一组翻转链表
解析代码
本篇完。 ①力扣2. 两数相加
2. 两数相加
难度 中等
给你两个 非空 的链表表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的并且每个节点只能存储 一位 数字。
请你将两个数相加并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外这两个数都不会以 0 开头。
示例 1 输入l1 [2,4,3], l2 [5,6,4]
输出[7,0,8]
解释342 465 807.示例 2
输入l1 [0], l2 [0]
输出[0]示例 3
输入l1 [9,9,9,9,9,9,9], l2 [9,9,9,9]
输出[8,9,9,9,0,0,0,1]提示
每个链表中的节点数在范围 [1, 100] 内0 Node.val 9题目数据保证列表表示的数字不含前导零
/*** Definition for singly-linked list.* 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* addTwoNumbers(ListNode* l1, ListNode* l2) {}
}; 解析代码 两个链表都是逆序存储数字的即两个链表的个位数、十位数等都已经对应可以直接相加。 在相加过程中要注意是否产生进位产生进位时需要将进位和链表数字一同相加。如果产生进位的位置在链表尾部即答案位数比原链表位数长一位还需要再new一个结点储存最高位。
/*** Definition for singly-linked list.* 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* addTwoNumbers(ListNode* l1, ListNode* l2) {ListNode *head new ListNode(0);ListNode *ret head;ListNode *cur1 l1, *cur2 l2;int carry 0; // 进位while(cur1 || cur2 || carry){int val carry;if(cur1){val cur1-val;cur1 cur1-next;}if(cur2){val cur2-val;cur2 cur2-next;}head-next new ListNode(val % 10);head head-next;carry val / 10;}return ret-next;}
}; ②力扣24. 两两交换链表中的节点
24. 两两交换链表中的节点
难度 中等
给你一个链表两两交换其中相邻的节点并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题即只能进行节点交换。
示例 1 输入head [1,2,3,4]
输出[2,1,4,3]示例 2
输入head []
输出[]示例 3
输入head [1]
输出[1]提示
链表中节点的数目在范围 [0, 100] 内0 Node.val 100
/*** Definition for singly-linked list.* 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* swapPairs(ListNode* head) {}
}; 解析代码
递归法在下面链接讲过
Offer必备算法07_递归_五道力扣题详解由易到难-CSDN博客 迭代法就是自己画图不要吝啬定义指针直接定义四个指针在前面new一个头结点视为prev让cur和next1交换然后四个指针像后走结束条件是cur或者next1为空。 /*** Definition for singly-linked list.* 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* swapPairs(ListNode* head) {ListNode *newHead new ListNode(0);if(head nullptr || head-next nullptr)return head;// newHead - 1 - 2 - 3// 1和2换 - cur和next1换// prev - cur - next1 - next2// cur - prev - next1 - next2ListNode *prevnewHead, *curhead, *next1head-next, *next2next1-next;while(cur next1){prev-next next1;next1-next cur;cur-next next2;prev cur;cur next2;if(cur)next1 cur-next;if(next1)next2 next1-next;}cur newHead-next;delete newHead;return cur;// 递归法// if(head nullptr || head-next nullptr)// return head;// ListNode* tmp swapPairs(head-next-next); // 把两个结点之外的看成另一部分// head-next-next head;// auto ret head-next; // 保存一下要返回的结点// head-next tmp;// return ret;}
}; ③力扣143. 重排链表
难度 中等
给定一个单链表 L 的头节点 head 单链表 L 表示为
L0 → L1 → … → Ln - 1 → Ln请将其重新排列后变为
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
不能只是单纯的改变节点内部的值而是需要实际的进行节点交换。
示例 1 输入head [1,2,3,4]
输出[1,4,2,3]
示例 2 输入head [1,2,3,4,5]
输出[1,5,2,4,3]提示
链表的长度范围为 [1, 5 * 10^4]1 node.val 1000
/*** Definition for singly-linked list.* 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:void reorderList(ListNode* head) {}
}; 解析代码
在C语言讲的数据结构里讲过这三道OJ
206. 反转链表
876. 链表的中间结点
21. 合并两个有序链表
这道题就是先找到中间结点分为两部分链表然后翻转后部分链表最后合并两个链表
/*** Definition for singly-linked list.* 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:void reorderList(ListNode* head) {if(headnullptr || head-nextnullptr || head-next-nextnullptr)return; // 处理边界情况ListNode *fast head, *slow head;while(fast fast-next) // 找到中间结点{slow slow-next;fast fast-next-next;}ListNode* slowNext slow-next;slow-next nullptr; // 两个链表断开slow slowNext;ListNode *reverseList nullptr;while(slow) // 中间结点后面的头插到翻转链表{slowNext slow-next;slow-next reverseList;reverseList slow;slow slowNext;}ListNode* tmp head; // 合并两个链表ListNode *cur1 head-next, *cur2 reverseList;while(cur1 cur2){tmp-next cur2;tmp tmp-next;cur2 cur2-next;tmp-next cur1;cur1 cur1-next;tmp tmp-next;}}
}; ④力扣23. 合并 K 个升序链表
23. 合并 K 个升序链表 难度 困难
给你一个链表数组每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中返回合并后的链表。
示例 1
输入lists [[1,4,5],[1,3,4],[2,6]]
输出[1,1,2,3,4,4,5,6]
解释链表数组如下
[1-4-5,1-3-4,2-6
]
将它们合并到一个有序链表中得到。
1-1-2-3-4-4-5-6示例 2
输入lists []
输出[]示例 3
输入lists [[]]
输出[]提示
k lists.length0 k 10^40 lists[i].length 500-10^4 lists[i][j] 10^4lists[i] 按 升序 排列lists[i].length 的总和不超过 10^4
/*** Definition for singly-linked list.* 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* mergeKLists(vectorListNode* lists) {}
}; 解析代码1小根堆优化 之前写过合并两个有序链表的题此题暴力解法就是依次合并两个有序链表合并K次。时间复杂度是ON*K^2是N^3级别的。 在暴力解法基础上可以使用小根堆优化合并 K 个升序链表时选择 K 个链表中头结点值最小的那⼀个的插入到新链表时间复杂度是ON*K*logK。下面是小根堆优化的代码
/*** Definition for singly-linked list.* 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 {struct cmp{bool operator()(const ListNode* l1, const ListNode* l2){return l1-val l2-val;}};public:ListNode* mergeKLists(vectorListNode* lists) {priority_queueListNode*, vectorListNode*, cmp heap;for(auto e : lists) // 所有头结点进入小根堆{if(e)heap.push(e);}ListNode* newHead new ListNode(0);ListNode* tmp newHead;while(!heap.empty()){ // 尾插堆顶结点到新链表再把旧链表下个结点插入小根堆ListNode* cur heap.top();heap.pop();tmp-next cur;tmp cur;if(cur-next){heap.push(cur-next);}}tmp newHead-next;delete newHead;return tmp;}
}; 解析代码2递归_归并
递归出口如果当前要合并的链表编号范围左右值相等无需合并直接返回当前链表。应用二分思想等额划分左右两段需要合并的链表使这两段合并后的长度尽可能相等。对左右两段分别递归合并[leftright]范围内的链表。最后调用合并两个链表函数进行合并。
/*** Definition for singly-linked list.* 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* mergeKLists(vectorListNode* lists) {return merge(lists, 0, lists.size() - 1);}ListNode* merge(vectorListNode* lists, int left, int right){if(left right) // 区间不存在return nullptr;if(left right) // 只有一个链表return lists[left];int mid (left right) 1;ListNode* list1 merge(lists, left, mid);ListNode* list2 merge(lists, mid1, right);// 上面递归得到一个/两个链表return mergeTwoLists(list1, list2);}ListNode* mergeTwoLists(ListNode* list1, ListNode* list2){if(list1 nullptr)return list2;if(list2 nullptr)return list1;if(list1-val list2-val){list1-next mergeTwoLists(list1-next, list2);return list1;}else{list2-next mergeTwoLists(list2-next, list1);return list2;}}
}; ⑤力扣25. K 个一组翻转链表
25. K 个一组翻转链表 难度 困难
给你链表的头节点 head 每 k 个节点一组进行翻转请你返回修改后的链表。
k 是一个正整数它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍那么请将最后剩余的节点保持原有顺序。
你不能只是单纯的改变节点内部的值而是需要实际进行节点交换。
示例 1 输入head [1,2,3,4,5], k 2
输出[2,1,4,3,5]示例 2 输入head [1,2,3,4,5], k 3
输出[3,2,1,4,5]提示
链表中的节点数目为 n1 k n 50000 Node.val 1000
进阶你可以设计一个只用 O(1) 额外内存空间的算法解决此问题吗
/*** Definition for singly-linked list.* 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* reverseKGroup(ListNode* head, int k) {}
}; 解析代码 可以把链表按 K 个为一组进行分组组内进行反转并且记录反转后的头尾结点使其可以和前后连接起来。先求出⼀共需要逆序多少组假设逆序 n 组然后重复 n 次长度为 k 的链表的逆序即可。
/*** Definition for singly-linked list.* 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* reverseKGroup(ListNode* head, int k) {int n 0;ListNode* cur head;while(cur){cur cur-next;n;}n / k;cur head;ListNode* newHead new ListNode();ListNode* prev newHead;while(n--){ListNode* tmp cur;int cnt k;while(cnt--){ListNode* prevNext cur-next;cur-next prev-next; // cur头插到prevprev-next cur;cur prevNext;}prev tmp;}prev-next cur;cur newHead-next;delete newHead;return cur;}
}; 本篇完。
下一篇动态规划的类型的路径dp类型的OJ。
下下篇数据结构类型的是哈希表类型的OJ。