LeetCode--有序链表合并

今天在LeetCode刷了一道有序链表合并的算法题,一开始是直接把L2链表直接插到了L1里面,后来觉得这样会把原来的L1破坏掉,所以又做了一个把L1、L2放到一个新链表的方法,而且感觉这样更加符合编程的规范(王道)
但这里把两种方法都写一下

方法一:L2插L1

思路:
第一步:先判断L1和L2是否有空的,做对应的处理;
第二步:从L2依次拿一个节点出来和L1每个节点比较大小,如果L2的节点小于L1的某个节点,就把L2节点插入到该L1节点的前面,直到L1或者L2其中有一个遍历完毕;
第三步:检查L2是否还有节点没有插入到L1里面,如果有则直接全部插入到L1后面

代码如下:


/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if(l1==null&&l2==null)
            return null;
        else if(l1!=null&&l2==null)
            return l1;
        else if(l2!=null&&l1==null)
            return l2;
        ListNode la=l1,lb=l2,lc=l1,head=l1,term=null;
        while(la!=null&&lb!=null){
            if(lb.val<la.val){
                term=lb;
                lb=lb.next;
                term.next=la;
                if(la==head){
                    lc=term;
                    head=lc;
                }
                else{
                    lc.next=term;
                    term.next=la;
                    lc=lc.next;
                }
            }
            else{
                lc=la;
                la=la.next;
            }
        }
        if(la==null&&lb!=null){
            lc.next=lb;
        }
        return head;
    }
}

LeetCode的时间复杂度和空间使用如下:
在这里插入图片描述

方法二:L1和L2合并到一个新的链表L3

思路:
第一步:先判断L1和L2是否有空的,做对应的处理;
第二步:把L1和L2依次各种拿一个节点出来比较,如果L1的节点小于L2的节点,就构造一个新的中介节点temp,把L1的节点的值放到temp节点里面去,然后把temp节点放到L3链表的后面(如果L3为空就把L3的头节点指向temp),如果L2的节点小于L1的节点就反过来,直到L1或者L2其中有一个遍历完毕;
第三步:检查L1或者L2是否还有节点没有插入到L1里面,如果有则直接全部插入到L3后面(也是要构造中介节点)

代码如下:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if(l1==null&&l2==null)
            return null;
        else if(l1!=null&&l2==null)
            return l1;
        else if(l2!=null&&l1==null)
            return l2;
        ListNode la=l1,lb=l2,lc=null,head=null,temp=null;
        while(la!=null&&lb!=null){
            if(lb.val<la.val){
                temp=new ListNode(lb.val);
                temp.next=null;
                lb=lb.next;
            }else{
                temp=new ListNode(la.val);
                temp.next=null;
                la=la.next;
            }
            if(head==null){
                head=temp;
                lc=head;
            }else{
                lc.next=temp;
                lc=lc.next;
            }
        }
        if(la==null&&lb!=null){
            while(lb!=null){
                temp=new ListNode(lb.val);
                lc.next=temp;
                lc=lc.next;
                lb=lb.next;
            }
        }else if(lb==null&&la!=null){
            while(la!=null){
                temp=new ListNode(la.val);
                lc.next=temp;
                lc=lc.next;
                la=la.next;
            }
        }
        return head;
    }
}

LeetCode的时间复杂度和空间使用如下:
在这里插入图片描述

小结

1、我在做第一个方法的时候总是有些粗心大意的地方,比如下面我把term指向lb之后居然忘了把lb指向下一位;以及当要插入的地方是头节点之前的时候我居然把lc.next指向了temp

 if(lb.val<la.val){
                term=lb;
                lb=lb.next;
                term.next=la;
                if(la==head){
                    lc=term;
                    head=lc;
                }

2、还有一个最严重的失误就是在程序的最开始忘了判断L1和L2是否有空的,做对应的处理,导致我在判断下面的条件的时候报了空指针异常,这一步里面我找了好久才找出这个错误,不过通过这个错误我也了解到了LeetCode编译器的RunCode是只是将测试数据(TestCode)放到你的程序里面运行,而Commint就会把各种各样的数据放到你的程序上运行,如果有一个测试用例不通过就会报错,我这个就是属于这种情况

 if(la==null&&lb!=null){
            lc.next=lb;
        }

3、两个方法的比较的话,空间上肯定是第二种方法开销更大,因为在L3新链表上面每次都要New一个新的储存空间;时间复杂度上也是第二种方法更大,因为最后还要通过循环来把剩余的L1和L2加入到L3里面去;但第二种方法比较简单,我个人觉得比较好理解,而且也比较符合实际操作(总不能把原来的L1和L2都破坏掉吧)

4、因为我做题都是选择用JAVA语言来做的,这次选到了链表的题目,说实话,这次是我第一次用Java来写链表(之前都是用C语言写的),因为Java里面操纵的标识符实际是指向一个对象的引用(说白了也就是C语言里面的指针),一开始很不习惯,总是下意识的以为是变量,所以还是要加油,看多点Java基础

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值