2.<tag-链表和归并, 优先队列>lt.21-合并两个有序链表 + lt.23-合并k个升序链表 dbc

lt.21-合并两个有序链表

[案例需求]
在这里插入图片描述

[思路分析一, 迭代法]

结合归并排序中的sort方法, 即可写出这道简单题
两条链表list1, list2, 在两者均未遍历到null时, 相互比较, 符合要求的加入到新链表中.

[代码实现]

/**
 * 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 mergeTwoLists(ListNode list1, ListNode list2) {
        //合并两个有序链表
        /**
            剪枝:
                list1 == null && list2 == null return 任意
                list1 == null || list2 == null 分别返回
            比较大小
            list1.val < list2  list1加入新链表, list1的temp后移

            = 均加入, 均后移

            > list2 加入, 后移.        
         */

        if(list1 == null && list2 == null) return null;
        if(list1 == null) return list2;
        if(list2 == null) return list1;

        ListNode temp1 = list1;
        ListNode temp2 = list2;
        ListNode dummyNode =  new ListNode(-1);
        ListNode temp = dummyNode;

        while(temp1 != null && temp2 != null){
            if(temp1.val <= temp2.val){
                 temp.next = temp1;
                temp1 = temp1.next;
                temp = temp.next;
            }else{
                temp.next = temp2;
                temp = temp.next;
                temp2 = temp2.next;
            }
        }

        if(temp1 != null)temp.next = temp1;
        if(temp2 != null)temp.next = temp2;

        return dummyNode.next;
    }
}

[思路分析二, 递归法]

在这里插入图片描述

[代码实现]

/**
 * 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 {
    //1.递归函数: 合并两个节点(list1和list2节点进行合并,)
    //返回值: 当前遍历处的头结点
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        //2. 递归出口
        if(list1 == null || list2 == null){
            return list1 == null ? list2 : list1;
        }

        //3. 单层递归逻辑
        //此时list1和list2均不为空
        //我们判断 l1 和 l2 头结点哪个更小,然后较小结点的 next 指针指向其余结点的合并结果。
        if(list1.val <= list2.val){
            list1.next = mergeTwoLists(list1.next, list2);
            return list1; // 返回给上一层的是更新后的头结点
        }else{
            list2.next = mergeTwoLists(list1, list2.next);
            return list2;// 返回给上一层的是更新后的头结点
        }
    }
}

lt.23-合并k个升序链表[hard]

[案例需求]
在这里插入图片描述
[思路分析]

  • 对于本题, 我们希望能够有一种数据结构, 把lists中的k条链表遍历后, 存入到其中, 在其中能够实现结点val之间的升序排列, 然后对这个数据结构遍历, 用next域把各个结点串起来即可, 想来想去, 最符合的就是优先队列(PriorityQueue)了, 它是一种基于堆(默认小顶堆)实现的数据结构.
  • 使用优先队列的解法步骤如下:
    0. 定义优先队列, 根据我们的需要传入比较器参数, new一个comparator, 重写他的compare方法让他能够按照我们想要的方式进行排序
    1. 遍历lists, 把遍历到的每个节点添加到priorityQueue中.
    2. 上一步骤完成后, 遍历priorityQueue, 并用一个指向头结点dummyNode的指针p把他们串起来, 返回头结点即可.

[代码实现]

/**
 * 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) {
        //1. 优先队列, 排序后存入,然后遍历优先队列处的节点都是有序的了, 我们直接连接起来即可
        if(lists == null || lists.length == 0)return null;
        PriorityQueue<ListNode> queue = new PriorityQueue(lists.length, 
            new Comparator<ListNode>(){
                public int compare(ListNode r1, ListNode r2){
                            return r1.val - r2.val;
                        }
       
            });
                        

        //2. 遍历链表节点数组
        for(ListNode node : lists){
            if(node != null)queue.add(node); // 注意, 这里每次存的只是数组中每条链表的头结点
            //为什么如此呢?  因为给定的k条链表都是升序的, 我们先存入头结点, 后面从队列中取出时边取边存即可
           // System.out.println(node.val);
        }

        //3. 遍历queue, 链接链表
        ListNode dummy = new ListNode(-1);
        ListNode temp = dummy;

        while(!queue.isEmpty()){
            temp.next = queue.poll(); //取出每条链表的头结点
            temp = temp.next; // 往后遍历;
            if(temp.next != null)queue.add(temp.next);//一边取出排好序的节点, 一边把这个节点后面的一个节点存入队列
        }

        return dummy.next;
    }
}

[思路分析二, 分治法]

待补充

posted @   青松城  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示