LeetCode高频题21. 合并两个有序链表

LeetCode高频题21. 合并两个有序链表

提示:本题是系列LeetCode的150道高频题,你未来遇到的互联网大厂的笔试和面试考题,基本都是从这上面改编而来的题目
互联网大厂们在公司养了一大批ACM竞赛的大佬们,吃完饭就是设计考题,然后去考应聘人员,你要做的就是学基础树结构与算法,然后打通任督二脉,以应对波云诡谲的大厂笔试面试题!
你要是不扎实学习数据结构与算法,好好动手手撕代码,锻炼解题能力,你可能会在笔试面试过程中,连题目都看不懂!比如华为,字节啥的,足够让你读不懂题
在这里插入图片描述


题目

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。


一、审题

示例:1
在这里插入图片描述
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
示例 2:

输入:l1 = [], l2 = []
输出:[]
示例 3:

输入:l1 = [], l2 = [0]
输出:[0]

提示:

两个链表的节点数目范围是 [0, 50]
-100 <= Node.val <= 100
l1 和 l2 均按 非递减顺序 排列

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/merge-two-sorted-lists
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。


笔试AC:链表转数组,再转链表

最蠢的办法就是拿个小根堆转移一下,或者数组转移排序,
然后挨个弹出重新组织为链表,空间复杂度高,适合笔试AC

问题不大:

public ListNode mergeTwoLists2(ListNode l1, ListNode l2) {
            //直接用小根堆,
            PriorityQueue<ListNode> heap = new PriorityQueue<>(new myComparator());
            while (l1 != null) {
                heap.add(l1);
                ListNode p1 = l1;
                l1 = l1.next;
                p1.next = null;
            }
            while (l2 != null) {
                heap.add(l2);
                ListNode p2 = l2;
                l2 = l2.next;
                p2.next = null;
            }
            ListNode head = heap.poll();
            ListNode cur = head;
            while (!heap.isEmpty()){
                cur.next = heap.poll();
                cur = cur.next;
            }

            return head;
        }

        public static class myComparator implements Comparator<ListNode>{
            @Override
            public int compare(ListNode o1, ListNode o2){
                return o1.val - o2.val;
            }
        }

测试一把:

public static void test(){
        ListNode l1 = new ListNode(1);
        ListNode l12 = new ListNode(2);
        ListNode l13 = new ListNode(3);
        l1.next = l12;
        l12.next = l13;

        ListNode l2 = new ListNode(1);
        ListNode l22 = new ListNode(3);
        ListNode l23 = new ListNode(4);
        l2.next = l22;
        l22.next = l23;

        Solution solution = new Solution();
        ListNode res = solution.mergeTwoLists2(l1, l2);
        while (res != null){
            System.out.print(res.val + " ");
            res = res.next;
        }
    }

    public static void main(String[] args) {
        test();
    }

测试一把:

1 1 2 3 3 4 
Process finished with exit code 0

看看LeetCode啥反应
在这里插入图片描述
在这里插入图片描述
就这方法已经很牛逼了

可以再尝试一下优化空间,别用堆,用少数俩变量,外部排序,谁小先挂谁

与归并排序算法中的merge过程一模一样
只不过这里是链表

【1】10大排序算法之四:归并排序【稳定的】,复杂度中,系统常用归并排序

(-1)4个变量
p1指向head1,next1=p1.next
p2指向head2,next2=p2.next

(0)对比p1和p2的值
(1)遇到p1<=p2,让p1.next=p2,然后n1和p1同步走,回到(0)
(2)遇到p1>p2,让p2.next=p1,然后n2和p2同步走,回到(0)
(3)直到n1或者n2为空,把剩下的转移完
在这里插入图片描述
比如,上图
(0)对比p1和p2的值
(1)遇到p1<=p2,让p1.next=p2,然后n1和p1同步走,看绿色那,回到(0)
得到的结果像这样
在这里插入图片描述

(2)遇到p1>p2,让p2.next=p1,然后n2和p2同步走,看橘色之后,粉色那,回到(0)
得到这样的结果
在这里插入图片描述
(1)遇到p1<=p2,让p1.next=p2,然后n1和p1同步走,看蓝色那,回到(0)
得到的结果像这样
在这里插入图片描述
(2)遇到p1>p2,让p2.next=p1,然后n2和p2同步走,看红色那,回到(0)
得到这样的结果
在这里插入图片描述

(3)直到n1或者n2为空,把剩下的转移完
在这里插入图片描述
手撕代码:
这个代码我可能设计有问题,思路是OK,但是细节没有扣出来,先放放,我的失误,后面补上。

后来我看了官方解题思想,人家那思路更简单

一个变量cur做结果,最开始cur随意指,然后
俩变量p1,p2分别指向l1,l2
外部排序
谁小,cur指向谁?
然后cur不断往下移
最后谁没了,转移另一个指针到cur
在这里插入图片描述
最开始cur指向-1
然后看看p1<=p2,看绿色那所以c指向p1,然后p1移动到橘色p1那,c移动到c的下一个位置,橘色c
然后看看p1>p2,所以c指向p2,然后p2移动到粉色p2那,c一移动到粉色c
然后看看p1<=p2,所以c指向p1,然后p1移动到蓝色p1那,c移动到c的下一个位置,蓝色c
然后看看p1>p2,所以c指向p2,然后p2移动到红色p2那,c一移动到红色c
然后看看p1<=p2,所以c指向p1,然后p1移动到null,c移动到c的下一个位置,紫色c

一旦p1,p2有一个是null,说明一条链表对比结束
将不null那个链表挂上c.next=p2完事,紫色那条线

自己不会就学习别人的做法
然后自己手撕,熟悉代码

//最优解:既可以省时间,又可以省空间
        public ListNode mergeTwoLists(ListNode l1, ListNode l2){
            //一个变量cur做结果,最开始cur随意指,然后
            ListNode ans = new ListNode(-1);//待会返回ans.next
            ListNode cur = ans;
            //俩变量p1,p2分别指向l1,l2
            ListNode p1 = l1;
            ListNode p2 = l2;
            //外部排序
            while (p1 != null && p2 != null){
                //谁小,cur指向谁?
                if (p1.val <= p2.val){
                    cur.next = p1;
                    p1 = p1.next;//不会断开的
                }else {
                    cur.next = p2;
                    p2 = p2.next;//不会断开的
                }
                //然后cur不断往下移
                cur = cur.next;
            }

            //最后谁没了,转移另一个指针到cur
            if (p1 == null) cur.next = p2;
            else cur.next = p1;//p2为null

            return ans.next;//-1开头
        }

测试一把:

    public static ListNode createList1(){
        ListNode l1 = new ListNode(1);
        ListNode l12 = new ListNode(2);
        ListNode l13 = new ListNode(4);
        l1.next = l12;
        l12.next = l13;

        return l1;
    }
    public static ListNode createList2(){
        ListNode l2 = new ListNode(1);
        ListNode l22 = new ListNode(3);
        ListNode l23 = new ListNode(4);
        l2.next = l22;
        l22.next = l23;

        return l2;
    }
    public static void test(){
        ListNode l1 = createList1();
        ListNode l2 = createList2();

        Solution solution = new Solution();

        ListNode res = solution.mergeTwoLists2(l1, l2);
        while (res != null){
            System.out.print(res.val + " ");
            res = res.next;
        }

        System.out.println();

        ListNode l3 = createList1();
        ListNode l4 = createList2();
        res = solution.mergeTwoLists(l3, l4);
        while (res != null){
            System.out.print(res.val + " ");
            res = res.next;
        }
    }

    public static void main(String[] args) {
        test();
    }

绝对屌爆了

1 1 2 3 4 4 
1 1 2 3 4 4 

代码非常简单,这个思路,自己记住了,非常非常非常简单
在这里插入图片描述


总结

提示:重要经验:

1)merge最简单的就是链表转数组,然后合并,外部排序,很容易。
2)实际上还有更简单的就是4个指针,同时控制往下走就完事
3)笔试求AC,可以不考虑空间复杂度,但是面试既要考虑时间复杂度最优,也要考虑空间复杂度最优。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

冰露可乐

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

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

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

打赏作者

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

抵扣说明:

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

余额充值