算法练习2:leetcode习题23. Merge k Sorted Lists

[TOC]

题目

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

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

算法思路

输入:k个从小到大排序好的链表
输出:合并k个链表后的结果链表

这道题的解法思路有很多,最直接的当然是把链表的所有数据遍历并记录在一个数组中,然后使用一些基本的排序算法例如冒泡排序,快速排序之类的。但这样的效率很低,也没有很好的利用了链表这个数据结构。
我们可以参照一下课堂上的分治的思想,把一个大问题转化成多个相同性质的小问题。为方便理解思路,我引用了标准解法里面的图
分治

现在问题变成了合并两个链表。假设初始k个链表的规模都相近,则上图的合并顺序是最优的,因为它保持了每一轮合并时操作的链表规模尽可能的小。
而合并两个链表的思路也很直接,不断比较两个链表的表头元素,取较小的元素到新的链表,直到其中某个链表元素取尽。

C++代码

/**
 * 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) {
    if (lists.size() == 0)
    {
      return NULL;
    }
    
    vector<ListNode*> nextlists;
    while(lists.size() != 1) {
      nextlists.clear();
      for(int i = 0; i < lists.size()/2; i++){
        nextlists.push_back(merge(lists[2*i], lists[2*i+1]));
      }
      if (lists.size() % 2 == 1)
      {
        nextlists.push_back(lists[lists.size()-1]);
      }
      lists.swap(nextlists);
    }

    return lists[0];
  }
//合并两个有序链表成一个有序链表
  ListNode* merge(ListNode *first, ListNode *second) {
    ListNode *head = new ListNode(0);
    ListNode *p = head;
    while(first != NULL && second != NULL){
      if (first->val < second->val)
      {
        p->next = first;
        first = first->next;
      }
      else{
        p->next = second;
        second = second->next;
      }
      p = p->next;
    }

    if (first != NULL)
    {
      p->next = first;
    }
    if (second != NULL)
    {
      p->next = second;
    }

    p = head->next;
    delete head;
    return p;
  }
};
原文链接:加载失败,请重新获取