笔试题36. LeetCode OJ (23)

来源:互联网 发布:h3c路由器查看端口ip 编辑:程序博客网 时间:2024/06/06 02:05

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





0 0
原创粉丝点击