LeetCode Top 100 Liked Questions 23. Merge k Sorted Lists (Java版; Hard)

welcome to my blog

LeetCode Top 100 Liked Questions 23. Merge k Sorted Lists (Java版; Hard)

题目描述

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
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        int n = lists.length;
        if(n==0){
            return null;
        }
        return mergeSort(lists, 0, n-1);
    }

    private ListNode mergeSort(ListNode[] lists, int L, int R){
        if(L>R){
            return null;
        }
        if(L==R){
            return lists[L];
        }
        int mid = L + (R-L)/2;
        ListNode left = mergeSort(lists, L, mid);
        ListNode right = mergeSort(lists, mid+1, R);
        return merge(left, right);
    }

    private ListNode merge(ListNode node1, ListNode node2){
        ListNode dummy = new ListNode(-1);
        ListNode cur = dummy;
        while(node1!=null && node2!=null){
            if(node1.val < node2.val){
                cur.next = node1;
                //
                node1 = node1.next;
                cur = cur.next;
            }else{
                cur.next = node2;
                //
                node2 = node2.next;
                cur = cur.next;
            }
        }
        if(node1!=null){
            cur.next = node1;
        }
        if(node2!=null){
            cur.next = node2;
        }
        return dummy.next;
    }
}
第二次做; 分治思想; 递归函数逻辑:将lists[left, right]这些链表合并, 先合并完lists[left,mid]这些链表, 再合并完lists[mid+1,right]这些链表, 然后将这两部分合并成一个大链表
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    //分而治之
    public ListNode mergeKLists(ListNode[] lists) {
        if(lists==null || lists.length==0)
            return null;
        ListNode head = mergeSort(lists, 0, lists.length-1);
        return head;
    }
    //递归函数逻辑: 将lists[left, right]这些链表合并, 先合并完lists[left,mid]这些链表, 再合并完lists[mid+1,right]这些链表, 然后将这两部分合并成一个大链表
    private ListNode mergeSort(ListNode[] lists, int left, int right){
        if(left==right)
            return lists[left];
        int mid = left + ((right-left)>>1);
        //先将lists[left,mid]这些链表合并
        ListNode head1 = mergeSort(lists, left, mid);
        //再将lists[mid+1,right]这些链表合并
        ListNode head2 = mergeSort(lists, mid+1, right);
        //最后将这两部分合并成一个大链表
        ListNode head = merge(head1, head2);
        return head;
    }
    
    //合并两个链表, 合并后仍有序; 递归函数逻辑: 找出head1和head2中值更小的节点cur, cur指向剩余的已经合并完的链表
    private ListNode merge(ListNode head1, ListNode head2){
        if(head1==null)
            return head2;
        if(head2==null)
            return head1;
        ListNode cur;
        if(head1.val<=head2.val){
            head1.next = merge(head1.next, head2);
            return head1;
        }
        else{
            head2.next = merge(head1, head2.next);
            return head2;
        }
    }
}
第一次做, 分治思想; 合并两个链表也可以改成递归的形式; 执行用时4ms ;内存消耗40.9MB; 比不用分治思想的方法快太多了…
  • input check要全面
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        //input check
        //开始没加lists.length==0的判断,导致lists.length==0时会无限调用ListNode leftHead = merge(lists, left, mid); 因为left==0, right==-1
        if(lists==null || lists.length==0)
            return null;
        return merge(lists, 0, lists.length-1);
    }
    //递归逻辑: 把前n/2个链表合成一个, 把后n/2个链表合成一个, 最后把合成后的两个链表再合成为一个链表
    //返回头结点
    public ListNode merge(ListNode[] lists, int left, int right){
        //base case
        if(left == right)
            return lists[left];
        int mid = left + ((right - left)>>1);
        ListNode leftHead = merge(lists, left, mid); //什么情况下这句会无限调用? input check时没有考虑list.length==0就会出现
        ListNode rightHead = merge(lists, mid+1, right);
        ListNode head = mergeTwo(leftHead, rightHead);
        return head;
    }
    //这个可以改成递归的形式
    public ListNode mergeTwo(ListNode leftHead, ListNode rightHead){
        if(leftHead==null)
            return rightHead;
        if(rightHead==null)
            return leftHead;
        if(leftHead.val < rightHead.val){
            leftHead.next = mergeTwo(leftHead.next, rightHead);
            return leftHead;
        }
        else{
            rightHead.next = mergeTwo(leftHead, rightHead.next);
            return rightHead;
        }
    }
}
第一次做, 看了题解后使用分治思想(看来归并就是分治思想; 二分就是分治思想); 执行用时5ms ;内存消耗42.6MB; 比不用分治思想的方法快太多了…
  • input check要全面
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        //input check
        //开始没加lists.length==0的判断,导致lists.length==0时会无限调用ListNode leftHead = merge(lists, left, mid); 因为left==0, right==-1
        if(lists==null || lists.length==0)
            return null;
        return merge(lists, 0, lists.length-1);
    }
    //递归逻辑: 把前n/2个链表合成一个, 把后n/2个链表合成一个, 最后把合成后的两个链表再合成为一个链表
    //返回头结点
    public ListNode merge(ListNode[] lists, int left, int right){
        //base case
        if(left == right)
            return lists[left];
        int mid = left + ((right - left)>>1);
        ListNode leftHead = merge(lists, left, mid); //什么情况下这句会无限调用? input check时没有考虑list.length==0就会出现
        ListNode rightHead = merge(lists, mid+1, right);
        ListNode head = mergeTwo(leftHead, rightHead);
        return head;
    }
    public ListNode mergeTwo(ListNode leftHead, ListNode rightHead){
        if(leftHead==null)
            return rightHead;
        if(rightHead==null)
            return leftHead;
        ListNode tempHead = new ListNode(0), curr = tempHead;
        while(leftHead!=null || rightHead!=null){
            if(leftHead.val < rightHead.val){
                curr.next = leftHead;
                //update
                leftHead = leftHead.next;
                curr =curr.next;
            }
            else{
                curr.next = rightHead;
                //update
                rightHead = rightHead.next;
                curr = curr.next;
            }
            if(leftHead==null){
                curr.next = rightHead;
                break;
            }
            if(rightHead==null){
                curr.next = leftHead;
                break;
            }
        }
        return tempHead.next;
    }
}
第一次做,多路归并, 核心思想和二路归并一样, 基础要牢牢掌握; 执行用时43ms ;内存消耗41.9MB
  • 竟然一次通过, 加油
/*
多路归并
核心思想和二路归并一样, 基础要牢牢掌握
*/
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        if(lists==null)
            return null;
        ListNode tempHead = new ListNode(0), curr = tempHead;
        while(true){
            boolean flag = false;
            for(int i=0; i<lists.length; i++){
                flag = flag | (lists[i]==null? false : true);
            }
            if(flag==false)
                break;
            int min = Integer.MAX_VALUE;
            for(int i=0; i<lists.length; i++){
                if(lists[i]!=null)
                    min = Math.min(min, lists[i].val);
            }
            for(int i=0; i<lists.length; i++){
                if(lists[i]!=null && lists[i].val==min){
                    curr.next = lists[i];
                    //upadte
                    lists[i] = lists[i].next;
                    curr = curr.next;
                }
            }
        }
        return tempHead.next;
    }
}
题解, 分治法, 两两合并; 想法很漂亮
class Solution {
   public ListNode mergeKLists(ListNode[] lists) {
        if (lists == null || lists.length == 0) return null;
        return merge(lists, 0, lists.length - 1);
    }

    private ListNode merge(ListNode[] lists, int left, int right) {
        if (left == right) return lists[left];
        int mid = left + (right - left) / 2;
        ListNode l1 = merge(lists, left, mid);
        ListNode l2 = merge(lists, mid + 1, right);
        return mergeTwoLists(l1, l2);
    }

    private ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if (l1 == null) return l2;
        if (l2 == null) return l1;
        if (l1.val < l2.val) {
            l1.next = mergeTwoLists(l1.next, l2);
            return l1;
        } else {
            l2.next = mergeTwoLists(l1,l2.next);
            return l2;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值