LeetCode-3:链表相加问题

这个题目属于中等难度

到底难在哪里呢

第一,基础便是如何理解链表的含义,看了题干才发现链表原来是一个对象链接一个对象,对象与对象之间通过next方法相连,而next方法对应的刚好是下一个对象,实际是val对应变量,next对应指针,取一个val,指针next左移一下。

第二,如何将链表相加并输出?

实际来言,它的输出顺序并不关键,关键点在于如何实现相加。

最早我的思路是,将两个链表先通过string保存下来,再将string转为Long或者Double类型数据,然后直接相加,再把得到的数据转为一个长字符串,然后从低到高循环这个字符串的char,一步步将它转换为链表。

看着是不是没啥问题?

但是很容易遇到暴力溢出的问题,原因在于,java中Long和Double最大支持精度范围只有64bit,也就是最大支持的精确十进制数只有2^63,即便是双精度,也不会比这个大!

一直出现溢出问题之后,我才发现这个问题的真正难点在于,即通过链表这一结构类型,实现任意长数字的加法。

任意长!

暂时看下来,链表没有长度限制。他的计算位数可以远超Long等包装数据类型。还有一个点是,各种数据在内存里面的存取是不是刚好和链表相同?

 官方思路:

  1. 对于任意一个链表,都通过LinkList.next 是否为null来判断是否到头,到头了,说明LinkList.val已经被加到计算里面去了,然后记findL1linklistEnd = true;下次不加也再也去找L1.next;

  2. 关于java中指针的概念:从此题目中,如何把链表反向以高bit最后放到尾巴上为最终目的。

如何理解: 开始新建两个链表,第一个链表 =  第二个链表,它们的其实指针地址相同,然后反复把第二个链表的尾巴向后延伸,最后再返回第一个链表,那么第一个链表的值,被第二个循环的延长了;

public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode resultListNode = null;
        ListNode endListNode = null;
        int add2NextBit = 0;
        boolean findL2End = false;
        boolean findL1End = false;
        while (true) {
            int bitValueL1 = 0;
            int bitValueL2 = 0;
            if(!findL1End) {bitValueL1 = l1.val;}
            if(!findL2End) {bitValueL2 = l2.val;}
            if (findL1End && findL2End && add2NextBit == 0) {
                break;
            }
            int bitValue = bitValueL1 + bitValueL2 + add2NextBit;
            if (bitValue >= 10) {
                add2NextBit = 1;
            } else {
                add2NextBit = 0;
            }
            if (resultListNode != null) {
//                resultListNode = new ListNode(bitValue % 10, resultListNode);
                endListNode.next = new ListNode(bitValue % 10);
                endListNode = endListNode.next;
            } else {
                resultListNode = new ListNode(bitValue % 10);
                endListNode = resultListNode;
            }
                if (!findL1End) {                                
                    l1 = l1.next;
                        if (l1==null) {findL1End = true;}
                    }
                if (!findL2End) {                    
                        l2 = l2.next;
                        if (l2==null) {findL2End = true;}
                }
                
                
            }
        return resultListNode;
    }

这个思路击败了99%的选手:

我的原始code 击败21%的选手  = =。

code view:

下面的code有多个影响速度的问题:

1. 利用try catch来增加容错,防止出现意外,结果就是这个逻辑非常慢,大概增加了 26ms时间(相比2ms);

2. 开始新建链表,输出结果为反的,最后又负负得正,这个方法好理解,就是先正着放,然后再先入先出;大概增加3ms时间;

public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
       ListNode resultListNode = null;
        int add2NextBit = 0;
        boolean findL2End = false;
        boolean findL1End = false;
        while (true) {
            int bitValueL1 = 0;
            int bitValueL2 = 0;
            if(!findL1End) {
                
                
                try {
                    bitValueL1 = l1.val;
                    // System.out.print( "bitValueL1 =  "+bitValueL1);
                } catch (Exception e) {
                    findL1End = true;
                    bitValueL1 = 0;
                    }
            }
            if(!findL2End) {
                try {
                bitValueL2 = l2.val;
                // System.out.println( "; bitValueL2 =  "+bitValueL2);
                }catch (Exception e) {
                    findL2End = true;
                    bitValueL2 = 0;
                }
            }
            if (findL1End && findL2End && add2NextBit == 0) {
                break;
            }
            int bitValue = bitValueL1 + bitValueL2 + add2NextBit;
            if (bitValue >= 10) {
                add2NextBit = 1;
            } else {
                add2NextBit = 0;
            }
            if (resultListNode != null) {
                resultListNode = new ListNode(bitValue % 10, resultListNode);
            } else {
                resultListNode = new ListNode(bitValue % 10);
            }
                try {                
                    l1 = l1.next;
                } catch (Exception e) {
                    findL1End = true;
                }
                try {
                    l2 = l2.next;
                } catch (Exception e) {
                    findL2End = true;
                }
                
            }
        ListNode reverseListNode = null;    
        while (true) {
            if (reverseListNode ==null) {
                reverseListNode = new ListNode(resultListNode.val);
            }else {                
                reverseListNode = new ListNode(resultListNode.val,reverseListNode);
            }
            if (resultListNode.next == null) {
                break;
            }
                resultListNode = resultListNode.next;
                
        }
        return reverseListNode;
    }

总结:

再一次体会到和大家的差距,学习到很多,感谢!

posted @ 2021-02-17 10:45  游泳的花生人-ATC  阅读(126)  评论(1编辑  收藏  举报