每天AC系列(九):合并K个排序链表

1 题目

LeetCode第23题,合并k个有序的链表.

2 暴力法

直接遍历所有链表,取出所有节点的值,用数组存储,非降序排序,然后创建一个新链表用头插法依次插入节点.

List<Integer> s = new ArrayList<>();
for(ListNode x:lists)
{
    while(x != null)
    {
        s.add(x.val);
        x = x.next;
    }
}
s.sort((a,b) -> {return a.compareTo(b);});
ListNode result = new ListNode(0);
ListNode t = result;
for(Integer x:s)
{
    t.next = new ListNode(x);
    t = t.next;
}
return result.next;


这里要注意一下,sort那里不能写成:

s.sort((a,b)->{return a>b ? 1 : -1;});

没有考虑到等于的情况,所以用compareTo代替:

s.sort((a,b)->{return a.compareTo(b);});

3 直接合并法

每次遍历所有链表,取出首节点的值,各个比较然后得出最小值,将最小值插入新链表,然后移动最小值所在的链表的指针,直到所有链表为空.

ListNode result = new ListNode(0);
ListNode t = result;
int len = lists.length;
int nullNodeNums = 0;
for(boolean [] b = new boolean[len];nullNodeNums<len;)
{
    int min = Integer.MAX_VALUE;
    int minIndex = -1;
    for(int index = 0;index<len;++index)
    {
        ListNode x = lists[index];
        if(x == null)
        {
            if(!b[index])
            {
                b[index] = true;
                ++nullNodeNums;
            }
        }
        else if(x.val < min)
        {
            min = x.val;
            minIndex = index;
        }
    }
    if(minIndex != -1)
    {
        t.next = new ListNode(min);
        t = t.next;
        lists[minIndex] = lists[minIndex].next;
    }
}
return result.next;

这里使用了一个布尔数组判断是否某个节点已经移动到尾部,即表示是否为空,为空的话跳过这个节点,不为空的话取其值,计算是否为最小值.得到最小值后,添加到结果节点中,并移动最小值所在链表的指针.

这个方法看起来慢得很啊.

4 优先队列

优先队列是上两个方法的结合,遍历所有节点,取值并根据其值确定优先级添加到优先队列中,然后依次出队,将出队的值直接插入到新链表中.

PriorityQueue<Integer> queue = new PriorityQueue<>();
for(ListNode x:lists)
{
    while(x != null)
    {
        queue.add(x.val);
        x = x.next;
    }
}
ListNode s = new ListNode(0);
ListNode t = s;
while(!queue.isEmpty())
{
    t.next = new ListNode(queue.poll());
    t = t.next;
}
return s.next;

java的优先队列可以直接add即可,按照默认出队序列(对于整数是小的先出)使用尾插法插入到新链表中.

嗯,好像还可以的样子,但是还是不够快.

5 两两合并法

合并k个链表,相当于合并2个链表k-1次,利用递归的思想,每次合并两个链表,将合并后的链表后返回作为下一个要合并的链表继续合并.

public ListNode mergeKLists(ListNode[] lists) {
    if (lists == null || lists.length == 0)
        return null;
    ListNode t = lists[0];
    for(int i=1;i<lists.length;++i)
        t = merge(t, lists[i]);
    return t;
}
//public ListNode merge(ListNode a,ListNode b)

merge为直接合并两个链表的操作,不难,就不贴代码了,首先赋值t为第一个链表,然后依次合并t与剩下的n-1个链表.

好慢啊.

6 分治法

分治法是两两合并法的改进,两两合并每次合并两个链表,分治法每次合并一半数量的链表,总体思想是这样的:想要得到最终有序的链表,若左半部分的链表与右半部分的链表都有序,则相当于合并两个有序链表,为了得到左半部分的有序链表,需要继续对左半部分进行一半的分割,再次分成左半部分与右半部分,然后再分,直到某部分只有一个链表,然后返回,以合并两个普通有序链表的方式合并两个返回的链表.

public ListNode f(int start,int end)
{
    int len = end - start;
    if(len <= 1)
        return lists[start];
    ListNode l = f(start,start+len/2);
    ListNode r = f(start+len/2,end);
    return merge(l, r);
}

代码非常简洁,一开始为判断递归的条件,区间长度小于等于1直接返回[start]的节点,然后递归合并左半部分与右半部分的节点.

一个字,舒服.
真快.

7 源码

github

码云

原文地址:https://www.cnblogs.com/Blueeeeeeee/p/12244567.html

时间: 2024-07-31 19:55:01

每天AC系列(九):合并K个排序链表的相关文章

合并k个排序链表

题目 合并k个排序链表,并且返回合并后的排序链表.尝试分析和描述其复杂度. 样例 给出3个排序链表[2->4->null,null,-1->null],返回 -1->2->4->null 解题 两两合并 合并ab得到c 合并cd得到e /** * Definition for ListNode. * public class ListNode { * int val; * ListNode next; * ListNode(int val) { * this.val =

[leetcode] 23. 合并K个排序链表

23. 合并K个排序链表 这个题算是考察代码功底吧,基本功,对变量与引用的理解. 不多说了,思路跟第21题基本一致,只不过从两个换成了多个 class Solution { public ListNode mergeKLists(ListNode[] lists) { List<ListNode> listNodes = new ArrayList<>(Arrays.asList(lists)); ListNode ans = new ListNode(Integer.MAX_VA

23. 合并K个排序链表

知乎ID: 码蹄疾 码蹄疾,毕业于哈尔滨工业大学. 小米广告第三代广告引擎的设计者.开发者: 负责小米应用商店.日历.开屏广告业务线研发:主导小米广告引擎多个模块重构: 关注推荐.搜索.广告领域相关知识; 题目 合并 k 个排序链表,返回合并后的排序链表.请分析和描述算法的复杂度.示例:输入:[ 1->4->5, 1->3->4, 2->6]输出: 1->1->2->3->4->4->5->6 分析 前面已经做过两个有序链表的合并,只

LeetCode 第23题 合并K个排序链表

/* 23. 合并K个排序链表 合并 k 个排序链表,返回合并后的排序链表.请分析和描述算法的复杂度. 示例: 输入:[ 1->4->5, 1->3->4, 2->6]输出: 1->1->2->3->4->4->5->6 */ /** * Definition for singly-linked list. public class ListNode { int val; ListNode next; ListNode(int * x

LeetCode 23. 合并K个排序链表(Merge Two Sorted Lists)

23. 合并K个排序链表 23. Merge k Sorted Lists 题目描述 合并 k 个排序链表,返回合并后的排序链表.请分析和描述算法的复杂度. LeetCode23. Merge k Sorted Lists困难 示例: 输入: [ ??1->4->5, ??1->3->4, ??2->6] 输出: 1->1->2->3->4->4->5->6 Java 实现 public class ListNode { int va

[LeetCode]23. 合并K个排序链表(优先队列;分治待做)

题目 合并?k?个排序链表,返回合并后的排序链表.请分析和描述算法的复杂度. 示例: 输入: [ ? 1->4->5, ? 1->3->4, ? 2->6] 输出: 1->1->2->3->4->4->5->6 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/merge-k-sorted-lists 著作权归领扣网络所有.商业转载请联系官方授权,非商业转载请注明出处. 题解 方法

leetcode(14)-合并k个排序链表

合并?k?个排序链表,返回合并后的排序链表.请分析和描述算法的复杂度. 示例: #输入: [ ? 1->4->5, ? 1->3->4, ? 2->6 ] #输出: 1->1->2->3->4->4->5->6 链接:https://leetcode-cn.com/problems/merge-k-sorted-lists 自己的思路 在k个链表中找到一个比较节点,然后把k个链表分成两部分,一部分都比比较节点小,一部分都比比较节点大,

Java实现 亚博体育LeetCode 23 合并K个排序链表

合并K个排序链表 合并 k 个排序链表,返回合并后的排序链表.请分析和描述算法的复杂度. 示例: 输入:[1->4->5,1->3->4,2->6]输出: 1->1->2->3->4->4->5->6 PS:直接用PriorityQueue自动排序,改写一下compare方法. /** Definition for singly-linked list. public class ListNode { int val; ListNod

leetCode 23. Merge k Sorted Lists (合并k个排序链表) 解题思路和方法

Merge k Sorted Lists Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. 思路:此题是由合并两个排序链表演化而来,刚开始,想法比较简单,像求最大公共前缀一样,逐一求解:但是最后超时,所以马上意识到出题方是为了使用归并和分治的方法,故重新写了代码. 代码一(超时未过): /** * Definition for singly-link