leetcode 倒序链表 两数相加

两数相加

题目:

image-20200714180708553

我的解法:

 /**
   * @Description TODO
   * @Param [l1, l2]
   * @return arrays.addTwoNumbers.ListNode
   * @date 2020/7/14 17:21
   * @author huanl
   *
   * 思路:先把他全部拿出来,拿出来的时候用字符串的append函数连接起来,后面再用reverse去反转.在把他们相加的到的
   * 数转换为StringBuilder类型,然后反转,然后在把他变成ListNode类型.
   *
   * 问题: 为什么要全部拿出来? 我们正常时候做加法,不就是从低位做起,然后有进位就记录一下,下一次添加上.现在链表他给我们就是已经弄好了的低位,
   * 直接从低位开始相加就好了.
   *        直接一个一个取然后加的话怎么判断他本身到底有没有值?  噢,直接判断这个节点是不是为null
   *        加到最后可能最后一次的进位记录为一,怎么处理?   再在后面多加一个节点,将这个一记录上去.
   */
    public  ListNode addTwoNumber(ListNode l1, ListNode l2) {
        
        //用StringBuilder取出l1和l2里面所有的
        StringBuilder num1 = new StringBuilder();
        StringBuilder num2 = new StringBuilder();
        num1.append(l1.val);
        num2.append(l2.val);
        while (l1.next != null) {
            num1.append(l1.next.val);
            l1 = l1.next;
        }
        while (l2.next != null) {
            num2.append(l2.next.val);
            l2 = l2.next;
        }
        //反转为正常的顺序
        num1 = num1.reverse();
        num2 = num2.reverse();

        //将两个字符串相加 (因为直接一次的话会超出int或者long的长度) 其实最好就是将他们逆转过来,这样才符合我们日常的加法
        int[] nums = new int[(Math.max(num1.length(), num2.length())) + 1];
        for (int i = 1; i <= (Math.max(num1.length(), num2.length())); i++) {
            if (i>num1.length()){
                nums[nums.length-i] = Integer.parseInt(String.valueOf(num2.charAt(num2.length()-i)));
            }else if(i>num2.length()){
                nums[nums.length-i] = Integer.parseInt(String.valueOf(num1.charAt(num1.length()-i)));
            }else {
                nums[nums.length-i] = Integer.parseInt(String.valueOf(num1.charAt(num1.length()-i))) + Integer.parseInt(String.valueOf(num2.charAt(num2.length()-i)));
            }

        }

        //处理进位信息
        for (int i = nums.length - 1; i > 0; i--) {
            nums[i-1] = nums[i-1] + nums[i] / 10;
            nums[i] = nums[i] % 10;
        }

        //因为两数相加可能会多一位,也就是第一位可能为1,可能为0,这里就先不处理第一位,直接从第二位开始处理
        StringBuilder num = new StringBuilder();
        for (int i = 1; i < nums.length ; i++) {
            num.append(nums[i]);
        }
        //处理第一位,如果为一,则直接插入最前面
        if (nums[0] != 0) {
            num.insert(0,nums[0]);
        }
        num = num.reverse();

        //将字符串类型的转化为ListNode类型
        ListNode ret = new ListNode(num.charAt(0) - 48);

        ListNode jilu = ret;

        for (int i = 1; i < num.length(); i++) {
            jilu.next = new ListNode(num.charAt(i) - 48);
            jilu = jilu.next;
    }
        return ret;

        }

问题:

  1. 为什么要先全部取出来? 有什么好处? 还是不能直接一个一个操作?

  2. 正是因为想要全部取出来,然后StringBuilder类型拼接快,然后StringBuilder又有一个反转函数,所以去用了StringBuilder,然后反转之后,本来想要用Integer.parseInt()转化为int然后相加,但是发现这个太容易直接超出范围,所以不得不直接用StringBuilder类型的直接相加,并且还用了反转之后的来相加,这就导致了相加函数复杂,并且相加之后,还需要处理进位信息,处理有没有多了一位的信息.

  3. 总结:

    1. 第一步的思路就问题,导致后续麻烦不断的到来,那为什么我会想取直接把他全部取出来呢?  
    	     没有取过多的考虑全部取出来有什么麻烦,就是简单就直接去取出来
    2. 能够去写出不定长字符串的加法,这个值得鼓励.
    

优解:

     /**
         * @Description TODO
         * @Param [l1, l2]
         * @return arrays.addTwoNumbers.ListNode
         * @date 2020/7/14 17:08
         * @author huanl
         */
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode dummyHead = new ListNode(0);
        ListNode p = l1, q = l2, curr = dummyHead;
        int carry = 0;
        while (p != null || q != null) {
            int x = (p != null) ? p.val : 0;
            int y = (q != null) ? q.val : 0;
            int sum = carry + x + y;
            carry = sum / 10;
            curr.next = new ListNode(sum % 10);
            curr = curr.next;
            if (p != null) p = p.next;
            if (q != null) q = q.next;
        }
        if (carry > 0) {
            curr.next = new ListNode(carry);
        }
        return dummyHead.next;
    }

优点:

1. 一个一个取,取出来直接进行操作,该进位的直接将进位符标志为1.
	为什么要一个一个取? 
		因为他给我们的就是符合加法计算规律的,也就是先从低位算起,有进位加到高位,并且链表取值的方向也正好是从低位到高位,各种条件都非常适合直接加.
2. 注意细节:
	a. 先建造一个头节点,这个头节点里面的值不和任何有关,那为什么要建一个这样的头节点呢? 因为没有这个头节点,第一次加法的时候就没有链表去操作,那么就势必需要把第一次提出来先做,这样就感觉有点不统一了.
	b. 用另外一个指针去操作,因为你需要返回这个链表,那么这个链表的头指针你必须保存一个,不然你就找不到这个指针了.
	c. 注意判断此时值到底取val还是0,判断条件是什么?  直接判断这个节点是不是空节点,因为我们操作的就是此节点,不是next节点.
	d. 注意可能最后一次加法时,进位为一,那么则需要在给他最后再加上一个节点,例如999+1就可能得到4位,这样就需要多加一个节点.

经验

  1. 先想一下怎么做,然后确定觉得这样做可以之后,把详细的思路写一遍,想一想为什么每一步需要这样做?和实际的相符吗?
    节点.
    d. 注意可能最后一次加法时,进位为一,那么则需要在给他最后再加上一个节点,例如999+1就可能得到4位,这样就需要多加一个节点.

## 经验

1. 先想一下怎么做,然后确定觉得这样做可以之后,把详细的思路写一遍,想一想为什么每一步需要这样做?和实际的相符吗?
2. 不定长字符串的加法,每位保存一个值的算法.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值