题目:
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 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 = [] 输出:[]
1.面对多个长短不一的链表,加上力扣直接给的如下函数,上来我就懵了,我寻思上一题是合并两个链表,这上来直接让我合并n个有点吓人,还有个没听过的vector,于是果断点开"题解"
ListNode* mergeKLists(std::vector<ListNode*>& lists)
2.代码如下
class Solution {
public:
ListNode* mergeTwoLists(ListNode *a, ListNode *b) {
if ((!a) || (!b)) return a ? a : b;
ListNode head, *tail = &head, *aPtr = a, *bPtr = b;
while (aPtr && bPtr) {
if (aPtr->val < bPtr->val) {
tail->next = aPtr; aPtr = aPtr->next;
} else {
tail->next = bPtr; bPtr = bPtr->next;
}
tail = tail->next;
}
tail->next = (aPtr ? aPtr : bPtr);
return head.next;
}
ListNode* mergeKLists(vector<ListNode*>& lists) {
ListNode *ans = nullptr;
for (size_t i = 0; i < lists.size(); ++i) {
ans = mergeTwoLists(ans, lists[i]);
}
return ans;
}
};
但是这串代码并不是贴在开头的,反而开头讲解了按升序合并两个链表的一般方法(相较于上一题的递归)
3.一般方法如下
ListNode* mergeTwoLists(ListNode *a, ListNode *b) {
if ((!a) || (!b)) return a ? a : b;
ListNode head, *tail = &head, *aPtr = a, *bPtr = b;
while (aPtr && bPtr) {
if (aPtr->val < bPtr->val) {
tail->next = aPtr; aPtr = aPtr->next;
} else {
tail->next = bPtr; bPtr = bPtr->next;
}
tail = tail->next;
}
tail->next = (aPtr ? aPtr : bPtr);
return head.next;
}
先创建一个指针,指向最终链表的头指针,即头指针的前一位,对两个链表进行对比,哪个链表的元素小就放到tail后面,直到一个链表为空停止,把剩下的接上,最后返回head的next
4.有了上述步骤就简单多了,把这个mergetwoLists放到mergeKLists里,然后循环就结束了
5.力扣的题解还是有点不严谨,这是经AI修改后的代码
ListNode* mergeKLists(std::vector<ListNode*>& lists) {
if (lists.empty()) return nullptr; // 如果列表为空,返回 nullptr
ListNode* ans = lists[0]; // 将 ans 初始化为第一个链表
for (size_t i = 1; i < lists.size(); ++i) {
ans = mergeTwoLists(ans, lists[i]); // 合并每个链表
}
return ans; // 返回合并后的链表
}
将ans初始化为nullptr可能会导致mergetwoLists出现问题,故用empty函数检查链表,如果空,返回nullptr即可,而将ans初始化为第一个链表更合理。
6.补充一下std::vector的用法
在 C++ 中,std::vector是一个动态数组容器,它允许你存储一系列元素,并且可以随时修改其大小。std::vector<ListNode*>表示一个存储指向 ListNode对象的指针的动态数组。在这个问题中,lists是一个 std::vector<ListNode*>,用于存储多个链表的头节点指针。
主要用法:
1.声明:你可以声明一个 vector,例如:
std::vector<ListNode*> lists;
这声明了一个空的 std::vector,它存储的是 ListNode* 类型(即链表节点指针)的元素。
2.添加元素:你可以使用 `push_back` 方法将元素添加到 `vector` 中:
lists.push_back(list1);
lists.push_back(list2);
这里,list1 和 list2 是指向链表的指针,它们会被添加到 lists 中。
3.访问元素:你可以通过下标或者迭代器访问 `vector` 中的元素:
ListNode* head = lists[0]; // 访问第一个链表
4.遍历:你可以使用范围 for 循环或传统的 for 循环来遍历 vector 中的元素:
for (auto list : lists) {
// 对每个链表的头节点进行操作
}
5.修改元素:你可以直接修改 vector 中的元素,前提是这些元素是指针或者对象:
lists[0] = new_head; // 修改第一个链表的头节点
6.大小:你可以使用 size() 方法来获取 vector 中元素的个数:
size_t size = lists.size();
总结:
std::vector 是 C++ 中非常常用的容器类,它可以存储多个元素,提供动态调整大小的能力。在这里,它被用来存储多个链表的头节点指针。你可以灵活地向 vector 中添加、访问和修改元素,同时可以利用其内置的高效操作来简化代码