Merge k Sorted Lists

Merge k Sorted Lists

问题:

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

思路:

  归并排序(二分问题)

我的代码:

public class Solution {
    public ListNode mergeKLists(List<ListNode> lists) {
        if(lists == null || lists.size() == 0) return null;
        if(lists.size() == 1) return lists.get(0);
        int n = lists.size();
        int i = 0;
        List<ListNode> left = new ArrayList<ListNode>();
        List<ListNode> right = new ArrayList<ListNode>();
        while(i < n/2)
        {
            left.add(lists.get(i));
            i++;
        }
        while(i < n)
        {
            right.add(lists.get(i));
            i++;
        }
        ListNode leftNode = mergeKLists(left);
        ListNode rightNode = mergeKLists(right);
        return mergeTwoLists(leftNode, rightNode);
    }
      public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode dummy = new ListNode(-1);
        ListNode rst = dummy;
        rst.next = null;
        while(l1 != null && l2 != null)
        {
            int val1 = l1.val;
            int val2 = l2.val;
            if(val1 < val2)
            {
                dummy.next = l1;
                l1 = l1.next;
            }
            else
            {
                dummy.next = l2;
                l2 = l2.next;
            }
            dummy = dummy.next;
        }
        if(l1 != null)
        {
            dummy.next = l1;
        }
        if(l2 != null)
        {
            dummy.next = l2;
        }
        return rst.next;
    }
}
View Code

他人代码1:

/*
        SOL 1:
          使用merge sort和分治法完成
    */
    public ListNode mergeKLists1(List<ListNode> lists) {
        // 记得加上这个合法性判断。
        if (lists == null || lists.size() == 0) {
            return null;
        }
        
        return helper(lists, 0, lists.size() - 1);
    }
    
    /*
    l, r表示list的左右边界
    */
    public ListNode helper(List<ListNode> lists, int l, int r) {
        if (l < r) {
            int mid = l + (r - l) / 2;
            
            /*
               分治法。把问题分为2个更小的子问题:左边list的merge,和右边list的merge.
               再把2个生成的解合并在一起。
            */
            return merge(helper(lists, l, mid), helper(lists, mid + 1, r));
        }
        
        return lists.get(l);
    }
    
    public ListNode merge(ListNode n1, ListNode n2) {
        ListNode dummy = new ListNode(0);
        ListNode cur = dummy;
        
        while (n1 != null && n2 != null) {
            if (n1.val < n2.val) {
                cur.next = n1;
                n1 = n1.next;
            } else {
                cur.next = n2;
                n2 = n2.next;
            }
            
            cur = cur.next;
        }
        
        if (n1 != null) {
            cur.next = n1;
        } else {
            cur.next = n2;
        }
        
        return dummy.next;
    }
View Code

他人代码2:

/*
        SOL 2:
          使用 priority Queue.
    */
    public ListNode mergeKLists(List<ListNode> lists) {
        // 记得加上这个合法性判断。
        if (lists == null || lists.size() == 0) {
            return null;
        }
        
        int size = lists.size();
        
        PriorityQueue<ListNode> q = new PriorityQueue<ListNode>(size, 
            new Comparator<ListNode>() {
                // 注意,此处参数用ListNode
                public int compare(ListNode o1, ListNode o2) {
                    return o1.val - o2.val;
                }
            }
        );
        
        // Add all the head node to the priority queue.
        for (ListNode node: lists) {
            if (node != null) {
                // Should skip the null node.s
                q.offer(node);    
            }
        }
        
        ListNode dummy = new ListNode(0);
        ListNode tail = dummy;
        
        while (!q.isEmpty()) {
            // get the smallest node from the queue.
            ListNode cur = q.poll();
            
            tail.next = cur;
            tail = tail.next;
            
            // 将下一个节点补充进来。
            if (cur.next != null) {
                q.offer(cur.next);
            }
        }
        
        return dummy.next;
    }
View Code

学习之处:

  • 此问题亦是二分查找的变形,我的方法是通过个数进行划分。
  • 而他人的代码通过left和right就比较成功了,对于递归中,left == right的情况也catch到了 left<right的地方也catch到了,十分完美的算法
  • 通过最小堆的方式亦可以解决这个问题,最小堆这个数据结果需要学习一下,建立堆的时间复杂度为O(nlgn),以当所有链表都读完时结束,这个时候所有元 素按从小到大放在结果链表中。这个算法每个元素要读取一次,即是k*n次,然后每次读取元素要把新元素插入堆中要logk的复杂度,所以总时间复杂度是 O(nklogk)。空间复杂度是堆的大小,即为O(k)

posted on 2015-03-13 09:50  zhouzhou0615  阅读(142)  评论(0编辑  收藏  举报

导航