23. 合并K个升序链表:给你一个链表数组,每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中,返回合并后的链表。

题目描述

给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。

示例 1:
输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6
示例 2:
输入:lists = []
输出:[]
示例 3:
输入:lists = [[]]
输出:[]

提示:
k == lists.length
0 <= k <= 10^4
0 <= lists[i].length <= 500
-10^4 <= lists[i][j] <= 10^4
lists[i] 按 升序 排列
lists[i].length 的总和不超过 10^4

思路

采用分治合并的思想解决

  1. 首先写一个方法合并两个链表
  2. 将数组中的链表进行配对(两个一组):第一轮合并以后, k 个链表被合并成了 k/2个链表,平均长度为2n/k,然后是k/4个链表, k/8个链表等等;如下图所示:
    在这里插入图片描述

代码

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        return merge(lists,0,lists.length-1);
    }
    //将一个数组中的多个链表划分为多个组(每个组两个链表),这些组分别进行合并
    /*
    lists:需要合并的链表数组
    first:当前链表数组最左边的下标(如:0)
    last:当前链表数组最右边的下标(如:lists.length-1)
    */
    public ListNode merge(ListNode[] lists,int first,int last){
        //如果最左边的下标到底最右边(证明已经得到需要合并的两个链表中的其中一个链表)
        if(first == last){
            return lists[first];
        }
        //如果最左边大于最右边下标(证明此时是匹配不上两个链表,所以只能为null)
        if(first > last){
            return null;
        }
        //>> :右移运算符,num >> 1,相当于num除以2
        int mid = (first+last) >> 1;
        //进行递归运算
        return mergeTwoLists(merge(lists,first,mid),merge(lists,mid+1,last));
    }
    //合并两个链表的方法
    public ListNode mergeTwoLists(ListNode a,ListNode b){
        //如果a为空,则把整个b以后的元素全部合并(b为空同理)
        if(a==null || b==null){
            return a!=null ? a : b;
        }
        //初始化一个节点值为0的空节点head来保存合并之后链表的头部
        ListNode head = new ListNode(0);
        //将tail指向head...
        ListNode tail = head,aPtr=a,bPtr=b;
        //当aPtr和bPtr都不为空时退出循环
        while(aPtr!=null && bPtr!=null){
            //如果aPtr当前的值小于bPtr,则将aPtr的值赋予tail
            if(aPtr.val < bPtr.val){
                //将aPtr的值赋予taail
                tail.next = aPtr;
                //aPtr往后移动一位
                aPtr = aPtr.next;
            }else{//与if里面的类似
                tail.next = bPtr;
                bPtr = bPtr.next;
            }
            //将当前tail的内容指向下一个结点
            tail = tail.next;
        }
        //最后两个链表中会剩下一个值(有一个链表不为空),将该值赋予当前tail的下一个结点
        tail.next = (aPtr!=null ? aPtr : bPtr);
        //将head返回,去除头节点的内容后
        return head.next;

    }
}

代码说明

见注释。。。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

?abc!

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

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

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

打赏作者

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

抵扣说明:

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

余额充值