合并K个排序链表,没错。我的思路是分别从 K 个链表的中找出最小的一个值,然后依次插入链表,最后遍历完所有链表就好了,也没想中的那么难呀,循环遍历的思路如下: (先说明一下,它是不合格的)
主要思路是:
1.首先从所有排序链表里找一个最小val节点作为头结点
2.依次循环在各个链表里面找到最小节点摘下来尾插,循环结束的条件是当链表的数目为0或者为1的时候结束(可以通过lists[i]==NULL来判断lists[i]代表的链表是否结束了),还编写了一个函数用来找最小元素下标的,每次返回的lists[i]的节点的val的值是"最小的"
3.但是这种做法有很多问题,当每个链表的长度都为1,但是总的数目很多的时候,效率太低,会有很多不必要的访问的(摘掉节点后的 lists 里面会有很多存放的是 NULL 指针),所以下面这种做法是无法达到时间限制的。
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists)
{
if(lists.size() == 0)
{
return NULL;
}
int pos = findmin(lists);
if(pos == -1)
{
return NULL;
}
ListNode *newHead=lists[pos];
lists[pos] = lists[pos]->next;
newHead->next = NULL;
ListNode* cur = newHead;
while(numOfList(lists)>1)
{
int pos = findmin(lists);
if(pos == -1)
{
break;
}
cur->next = lists[pos];
lists[pos] = lists[pos]->next;
cur = cur->next;
cur->next=NULL;
EraseList(lists);
}
if( numOfList(lists) == 1)
{
int lastpos = findmin(lists);
cur->next = lists[lastpos];
}
return newHead;
}
int numOfList(vector<ListNode*>&lists)
{
int num = 0;
int len = lists.size();
while(--len)
{
if(lists[len])
{
++num;
}
}
return num;
}
int findmin(vector<ListNode*>& lists)
{
int minval = 0;
int minpos = -1;
int j=0;
for( ;j<lists.size();++j)
{
if(lists[j])
{
minval=lists[j]->val;
minpos=j;
break;
}
}
for(int i=j+1;i<lists.size();++i)
{
if(lists[i] == NULL)
{
continue;
}
if(lists[i]->val < minval)
{
minval=lists[i]->val;
minpos = i;
}
}
return minpos;
}
void EraseList(vector<ListNode*>& lists)
{
int pos = 0;
while(lists[pos] == NULL)
{
++pos;
}
lists.erase(lists.begin(),lists.begin()+pos);
}
};
-------------------写了好几个函数才实现的,居然效率不达标,那么这时候必须换种想法了--------------
分治
对,我们可以通过分治的想法来实现,我们把大任务分为子任务,最后再汇总起来不就行了。所以我通过归并的思路去解题的,思路如下:
1.先把 k 个链表无限二等分并且递归进去
2.当区间的长度为1时,直接返回上一级,说明已经完成了这一趟的合并
3.当区间的长度为2时,合并这两个链表,在把结果返回上一级
4........最后,在把第一次分开的两个分支合并-------------------这就转化为了 k/2 次合并两个链表的思想(合并次数大于K/2)
代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists)
{
/*
合并k个排序链表
极端情况是n个只有一个节点的链表
所以不能循环的去做,我想到了归并排序的方法
*/
ListNode *list1;
ListNode *list2;
//归并排序
int len = lists.size();
if(len == 0)
{
return NULL;
}
if(len == 1)
{
return lists[0];
}
int mid=len/2;
domerge(list1,lists,0,mid);
domerge(list2,lists,mid+1,len-1);
ListNode *newHead = merge(list1,list2);
return newHead;
}
void domerge(ListNode*& list,vector<ListNode*>&lists,int begin,int end)
{
if(begin > end)
{
list=NULL;
}
if(begin == end)
{//返回
list=lists[begin];
}
if(end-begin == 1)
{//合并
list=merge(lists[begin],lists[end]);
}
if(end-begin >1)
{//继续二分
int mid = begin+(end-begin)/2;
ListNode *l1;
ListNode *l2;
domerge(l1,lists,begin,mid);
domerge(l2,lists,mid+1,end);
list=merge(l1,l2);
}
}
ListNode *merge(ListNode *l1,ListNode *l2)
{
if(l1 == NULL && l2==NULL)
{
return NULL;
}
if(l1 == NULL)
{
return l2;
}
if(l2 == NULL)
{
return l1;
}
ListNode *ret = NULL;
if(l1->val <= l2->val)
{
ret = l1;
l1 = l1->next;
}
else
{
ret = l2;
l2 = l2->next;
}
ret->next = NULL;
ListNode* cur = ret;
while(l1 && l2)
{
if(l1->val <= l2->val)
{
cur->next = l1;
l1 = l1->next;
cur=cur->next;
}
else
{
cur->next = l2;
l2 = l2->next;
cur = cur->next;
}
cur->next = NULL;
}
if(l1)
{
cur->next = l1;
}
if(l2)
{
cur->next = l2;
}
return ret;
}
};
结果是同过所有测试用例,包括第一种解法遇到的问题