合并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; } };
结果是同过所有测试用例,包括第一种解法遇到的问题
时间: 2024-10-12 16:15:52