(每周5题)之 leetcode题目 --- (23 合并K个升序链表)

       过完国庆节,在假期中没有去写有关leetcode题目,今天会慢慢分析题目,今天是23题,是个困难的的题目,但是我拿到题目就像到了最基本的解法,下面我们来看看吧!

 第二十三题:合并K个升序链表

 解题思路:拿到这个题目后,我的想法是,合并2个链表的做法,然后在顺序合并,这样时间复杂度就是0(k^2 * N)空间复杂   度可为0(1),第二个想法是比较第一个数据最小,然后使用优先队列优化,然后统一合并。本例子采用了第一个想法。

代码:

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) {}
	
};

//方法1  合并法
ListNode * mergeList(ListNode * result, ListNode * curList)
{
	if ( (!result) || (!curList))
	{
		return result ? result : curList;
	}
	ListNode  head, * nowlist = &head, *reslist = result, *cur = curList;
	while (reslist && cur)
	{
		if (reslist->val < cur->val)
		{
			nowlist->next = reslist; reslist = reslist->next;
		}
		else
		{
			nowlist->next = cur; cur = cur->next;
		}
		nowlist = nowlist->next;
	}
	nowlist->next = (reslist ? reslist : cur);
	return head.next;
}


ListNode* mergeKLists(vector<ListNode*>& lists) {
	ListNode * result = nullptr;
	for (int i = 0; i < lists.size();++i)
	{
		result = mergeList(result,lists[i]);
	}
	return result;
}

然后去找了官方对应的解答,使用priority_queue (优先队列)

解答连接:https://leetcode-cn.com/problems/merge-k-sorted-lists/solution/c-you-xian-dui-lie-liang-liang-he-bing-fen-zhi-he-/

优先队列

 代码:

    // 小根堆的回调函数
    struct cmp{  
       bool operator()(ListNode *a,ListNode *b){
          return a->val > b->val;
       };

    ListNode* mergeKLists(vector<ListNode*>& lists) {
        priority_queue<ListNode*, vector<ListNode*>, cmp> pri_queue;
        // 建立大小为k的小根堆
        for(auto elem : lists){
            if(elem) pri_queue.push(elem);
        }
        // 可以使用哑节点/哨兵节点
        ListNode dummy(-1);
        ListNode* p = &dummy;
        // 开始出队
        while(!pri_queue.empty()){
            ListNode* top = pri_queue.top(); pri_queue.pop();
            p->next = top; p = top;
            if(top->next) pri_queue.push(top->next);
        }
        return dummy.next;  
    }

时间复杂度:考虑优先队列中的元素不超过 k 个,那么插入和删除的时间代价为 O(logk),这里最多有 kn 个点,对于每个点都被插入删除各一次,故总的时间代价即渐进时间复杂度为 O(kn×logk)。
空间复杂度:这里用了优先队列,优先队列中的元素不超过 k 个,故渐进空间复杂度为 O(k)。

官方同时给出了分治合并:

故渐进时间复杂度为O(kn×logk)。 空间复杂度:递归会使用到 O(logk) 空间代价的栈空间。

代码:

    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* merge(vector <ListNode*> &lists, int l, int r) {
        if (l == r) return lists[l];
        if (l > r) return nullptr;
        int mid = (l + r) >> 1;
        return mergeTwoLists(merge(lists, l, mid), merge(lists, mid + 1, r));
    }

    ListNode* mergeKLists(vector<ListNode*>& lists) {
        return merge(lists, 0, lists.size() - 1);
    }

 已上就是这个题目的解法了。有关优先队列可以查看相应的数据结构,与stl。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值