Question

Q1.Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.

Example:

Input: 1->2->4, 1->3->4
Output: 1->1->2->3->4->4

Q2.Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.

Example:

Input:
[
  1->4->5,
  1->3->4,
  2->6
]
Output: 1->1->2->3->4->4->5->6

  在解决将k个已排序(从小到大)好的链表合并成一个已排序(从小到大)的链表前,我们先从一个特例开始,即将两个链表合并成一个。

Answer

1.合并两个排列好的链表

  问题就是将两个已排序的链表合并成一个,这是归并排序里的一个基本操作。

现在描述以下解决这个问题的算法,用数组来描述。

  我们输入两个数组,设为A,B,输出输出C,加入三个计数器Aptr,Bptr,Cptr,初始化为数组开头。

  取A[Aptr]和B[Bptr]的较小值拷贝到C的下一个位置,相应的计数器加一,重复该操作,直到某个计数器指向的索引值大于数组的边界。

  这时候代表一个数组的元素已经全部拷贝到C的相应位置了,我们将另一个数组剩下的元素拷贝到C里。

  回到Leetccode的这个问题,从链表的角度,计数器和链表元素可以用指针来代替,输入和输出数组也可以通过链表头指针访问,下面通过不完整的代码实现这个算法的思想。

ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
// first_Node用来输出链表, last_Node用作上面算法描述的计数器(即Cptr),也用作插入元素,代表输出C的最后一个节点
ListNode *first_Node = NULL, *last_Node = NULL;
// 在两个数组都没被拷贝到C时的操作。
while (l1 != NULL && l2 != NULL) {
// 判断A[Aptr](与l1->val一致),B[Bptr](与l2->val一致)哪个较小,将较小的插入到链表C的最后,Aptr和Bptr相应加一(相当于l1,l2)

if (l1->val > l2->val) {
last_Node->next = l2;
last_Node = last_Node->next;
l2 = l2->next;
}
else {
last_Node->next = l1;
last_Node = last_Node->next;
l1 = l1->next;
} }
// 将剩下的元素插入到C的最后
if (l1 == NULL && l2 != NULL) {
last_Node->next = l2;
}
else if (l1 != NULL && l2 == NULL) {
last_Node->next = l1;
}
// 返回链表C
return first_Node;
}

  上面的代码已经很能体现代码的具体思想了,剩下的工作就是将代码完善,将边界的情况考虑周全,实际呢,这又是特别麻烦的,一个不小心就会出现问题,比如说访问空指针。我们仔细考虑就会知道,上面代码没有对first_Node进行初始化,所以我们需要对first_Node判断是否为空,空就要初始化为对应的节点。那么在哪里判断呢,很容易想到,我们需要在判断A[Aptr]和B[Bptr]哪个较小后加入,然而这还没结束,将剩下的元素插入到C的最后 后的代码也没有对first_Node(last_Node)是否为空作判断,可又有对last_Node进行操作,这是十分危险的,所以我们也要在这里加入判断。最后完整的代码如下:

 ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode *first_Node = NULL, *last_Node = NULL;
while (l1 != NULL && l2 != NULL) { if (l1->val > l2->val) {
if (first_Node == NULL) {
first_Node = l2;
last_Node = first_Node; }
else {
last_Node->next = l2;
last_Node = last_Node->next;
}
l2 = l2->next;
}
else {
if (first_Node == NULL) {
first_Node = l1;
last_Node = first_Node; }
else {
last_Node->next = l1;
last_Node = last_Node->next;
}
l1 = l1->next;
} }
if (l1 == NULL && l2 != NULL) {
if (first_Node == NULL)
first_Node = l2;
else
last_Node->next = l2;
}
else if (l1 != NULL && l2 == NULL) {
if (first_Node == NULL)
first_Node = l1;
else
last_Node->next = l1;
}
return first_Node;
}

2.合并k个排列好的链表

  好了,有了上面的例子,我们合并k的链表也会有思路了,模仿上面算法的思路,我们可以每次将k个链表的最小值比较一遍,取最小值,将其拷贝到输出链表C中,当然这是可行的,时间复杂度为O(kN),N为最后剩下链表的长度,想了想感觉这有点麻烦,所以我们不妨考虑另一种方法。

  按照上一题的思路,其实我们可以两两链表合并,最后合并成一个链表,这样我们就可以重用上面的代码了。两两合并可以是链表1和链表2合并后的链表 再和链表3合并,以此类推,也可以是链表1和链表2合并为链表①,链表3和链表4合并为链表②,依次类推,①又和②合并……,如下图所示。聪明的你一比较就知道后者的效率会高很多,因为合并的次数明显变少了。因此,我们根据后者编写代码:

  

   ListNode* mergeKLists(vector<ListNode*>& lists) {
// 递归终止的条件
if (lists.size() == )
return NULL;
if (lists.size() == )
return lists[]; // 返回链表头节点指针

vector<ListNode*> tmpVec;
// 每两个链表合并
for (int i = ; i < lists.size()/*; i += )
tmpVec.push_back(mergeTwoLists(lists[i], lists[i+]));
// 如果k为奇数,将剩下的最后一个加入到tmpVec中
if (lists.size()% != )
tmpVec.push_back(lists[lists.size()-]);
// 继续合并
return mergeKLists(tmpVec);
}

  实际上,这样的解决办法称为分治(divide and conquer),将一个大问题分为几个子问题来解决,在编程里经常用递归实现,上面就有所体现。

Leetcode Week3 Merge Two(k) Sorted Lists的更多相关文章

  1. 乘风破浪:LeetCode真题_023_Merge k Sorted Lists

    乘风破浪:LeetCode真题_023_Merge k Sorted Lists 一.前言 上次我们学过了合并两个链表,这次我们要合并N个链表要怎么做呢,最先想到的就是转换成2个链表合并的问题,然后解 ...

  2. [Leetcode][Python]23: Merge k Sorted Lists

    # -*- coding: utf8 -*-'''__author__ = 'dabay.wang@gmail.com' 23: Merge k Sorted Listshttps://oj.leet ...

  3. 蜗牛慢慢爬 LeetCode 23. Merge k Sorted Lists [Difficulty: Hard]

    题目 Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity ...

  4. 【leetcode】Merge k Sorted Lists

    Merge k Sorted Lists Merge k sorted linked lists and return it as one sorted list. Analyze and descr ...

  5. 【LeetCode练习题】Merge k Sorted Lists

    Merge k Sorted Lists Merge k sorted linked lists and return it as one sorted list. Analyze and descr ...

  6. LeetCode之“链表”:Merge Two Sorted Lists && Merge k Sorted Lists

    1. Merge Two Sorted Lists 题目链接 题目要求:  Merge two sorted linked lists and return it as a new list. The ...

  7. LeetCode: Merge k Sorted Lists 解题报告

    Merge k Sorted Lists Merge k sorted linked lists and return it as one sorted list. Analyze and descr ...

  8. Leetcode 23.Merge Two Sorted Lists Merge K Sorted Lists

    Merge Two Sorted Lists Merge two sorted linked lists and return it as a new list. The new list shoul ...

  9. LeetCode 023 Merge k Sorted Lists

    题目要求:Merge k Sorted Lists Merge k sorted linked lists and return it as one sorted list. Analyze and ...

随机推荐

  1. mac 经常使用的快捷键操作

    ##### touch bar 作用1: 打开项目的一些快捷操作键. 作用2: 右侧的< 打开有一些以前的常规操作. ##### 手势 #####  mac自带的一些操作 cmd + opt + ...

  2. python随用随学20200220-异步IO

    啥是异步IO 众所周知,CPU速度太快,磁盘,网络等IO跟不上. 而程序一旦遇到IO的时候,就需要等IO完成才能进行才能进行下一步的操作. 严重拖累了程序速度. 因为一个IO操作就阻塞了当前线程,导致 ...

  3. 【公告】Hello World!

    Hi! 这里 是 华中师大一附中 2019 级信息组 官方博客 ! ^_^ 我们将在这里分享一些难题的做法,帮助大家共同学习. 也欢迎同是OIer的你加入我们哦!

  4. SpringBoot安全管理--(一)SpringSecurity基本配置

    简介: Spring Boot针对Spring Security提供了自动化配置方案,因此可以使Spring Security非常容易地整合进Spring Boot项目中,这也是在Spring Boo ...

  5. SpringBoot整合NoSql--(四)Session共享

    简介: 正常情况下,HttpSession是通过Servlet 容器创建并进行管理的,创建成功之后都是保存在内存中.如果开发者需要对项目进行横向扩展搭建集群,那么可以利用一些硬件或者软件工具来做负载均 ...

  6. P2094运输

    -------------------- 链接:Miku ------------------- 这是一道水贪心,很容易想到做法就是把最贵的两个放在一块,让后当成一个重新放回队列 ---------- ...

  7. 剑指offer-面试题60-n个骰子的点数-动态规划

    /* 题目: 计算n个骰子,出现和s的概率. */ #include<iostream> #include<cstdlib> #include<stack> #in ...

  8. echarts--可拖动的曲线图

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. java-重写

    重写有要求 1. 方法名:必须和父类被重写的方法名相同 2. 形参列表:必须和父类被重写的方法名相同 3. 返回值类型: A. 基本数据类型和void:要求与父类被重写的返回值数据类型一致 B. 引用 ...

  10. NIO学习笔记,从Linux IO演化模型到Netty—— 从BIO到epoll模型

    本文不涉及具体代码,只分析Linux IO演化的心路历程,学习资料来源网络,不保证一定正确,若有错误,欢迎指出. BIO 服务端创建socket(80端口),文件描述符3号. 当线程调用accept时 ...