牛客Top200---合并k个有序链表(java)

题目

在这里插入图片描述

分析

首先你要会写合并两个有序链表,这个题目就是合并两个链表的变形,如果懂合并两个,那么合并k个也就不难了,只要弄一个遍历即可,一开始最前面两个合并,将合并的结果与第一个合并,以此类推,每次都进行两个两个合并,知道和最后一个合并完毕,思路都不难

顺序合并

import java.util.*;

public class Solution {
    public ListNode mergeKLists(ArrayList<ListNode> lists) {
        //思路:k个有序链表合并,就是进行多次两个有序链表的合并
        //首先若k=0,即为空,则直接返回null
        if(lists == null || lists.size() == 0){
            return null;
        }
        //若k=1,则直接返回这个链表,无需要排序
        if(lists.size() == 1){
            return lists.get(0);
        }
        //若k>1,则执行合并,先前两个合并,将合并后的结果再和后面的链表合并
        //遍历合并
        ListNode node = lists.get(0);
        for(int i = 1 ; i < lists.size() ; i++){
            node = mergeTwoList(node,lists.get(i));
        }
        return node;
    }
    
    private ListNode mergeTwoList(ListNode node1,ListNode node2){
        ListNode temp = new ListNode(-1);//头结点,记录两个合并的链表
        ListNode node = temp;//记录这个头结点,后面用于返回合并后的第一个节点node.next
        while(node1 != null && node2 != null){
            //小的先连到temp的后面
            if(node1.val < node2.val){
                temp.next = node1;
                node1 = node1.next;
            }else{
                temp.next = node2;
                node2 = node2.next;
            }
            temp = temp.next;
        }
        //若node1或者node2没有执行完,则直接连接到temp后面
        if(node1 != null){
            temp.next = node1;
        }
        if(node2 != null){
            temp.next = node2;
        }
        //返回合并后的第一个节点
        return node.next;
    }
}

在这里插入图片描述
下面是LeetCode,顺序合并

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        //合并k个有序链表就是合并两个有序链表的升级,只要遍历lists,两个两个合并即可
        ListNode res = null;
        int len = lists.length;
        for(int i = 0 ; i < len ; i++){
            res = mergeTwoList(res,lists[i]);
        }
        return res;
    }
    private ListNode mergeTwoList(ListNode l1, ListNode l2){
        //处理初始传递过程中存在的null
        if(l1 == null || l2 == null){
            return l1 == null ? l2 : l1;
        }
        //l1和l2均!=null,进行合并
        //创建一个头节点
        ListNode head = new ListNode(-1);
        ListNode cur = head;
        while(l1 != null && l2 != null){
            if(l1.val <= l2.val){
                cur.next = l1;
                cur = cur.next;
                l1 = l1.next;
            }else{
                cur.next = l2;
                cur = cur.next;
                l2 = l2.next;
            }
        }
        if(l1 != null){
            cur.next = l1;
        }
        if(l2 != null){
            cur.next = l2;
        }
        return head.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];
        //left != right
        int mid = (left + right) / 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){
        //处理初始传递过程中存在的null
        if(l1 == null || l2 == null){
            return l1 == null ? l2 : l1;
        }
        //l1和l2均!=null,进行合并
        //创建一个头节点
        ListNode head = new ListNode(-1);
        ListNode cur = head;
        while(l1 != null && l2 != null){
            if(l1.val <= l2.val){
                cur.next = l1;
                cur = cur.next;
                l1 = l1.next;
            }else{
                cur.next = l2;
                cur = cur.next;
                l2 = l2.next;
            }
        }
        if(l1 != null){
            cur.next = l1;
        }
        if(l2 != null){
            cur.next = l2;
        }
        return head.next;
    }
}

在这里插入图片描述

总结

当数据量大时,顺序合并和归并合并,速度基本不在一个量级,一个100ms+,一个1ms,所以我们这里用归并

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小样x

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值