2、中等算法题:两数相加

题目:给出两个非空的链表,分别用来表示两个非负的整数。其中,它们各自的位数是按逆序的方式来存储的,并且它们的每个节点只能存储一位数字。如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。

可以假设这两个数都不会以0开头。

 

示例1:

输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)

输出:7 -> 0 -> 8

原因:342 + 465 = 807

 

这是一个很标准的示例,两个链表中存储的都是三位数,这个示例看不出更多的信息,接下来我再写几个示例:

示例2:

输入:(2)+(8)

输出:0 -> 1

原因:2 + 8 = 10

 

示例3:

输入:(7)+(7 -> 9 -> 9)

输出:4 -> 0 -> 0 -> 1

原因:7 + 997 = 1004

 

从这两个示例中,我们可以看到实现代码的一些问题,如下:

  • 两个链表的长度不一样,该如何处理?
  • 进位该如何处理?
  • 有时候进位会产生新的节点如何处理?

思路:刚看到这道题的时候,我当时想创建一个新的链表用来存储这两个数相加的计算结果。但是,考虑到如果将进位存储到新链表,则新链表也需要参与运算,这稍微增加了一些复杂性(个人感觉)。而这两个数本身就是存储在两个链表中,如果用其中一个链表来存储结果并进行运算,就足够。

如果存储两个数的链表长度不一致,只需给短的链表补足即可。而进位产生新节点,则只会出现在两个数的最高位相加大于10的情况下,此时只要新增一个节点存储进位,并且让结果链表的最后一个节点的后继指针指向该新增节点即可。

 

以【示例3】为例,计算步骤如下图:

①、假设以存储数字7的链表L1来存储计算结果,原始状态如下:

2、中等算法题:两数相加_第1张图片

②、逐位相加,对10取余,将取余结果存储到L1的当前参与计算的节点中,如下图:

2、中等算法题:两数相加_第2张图片

③、因为L1缺少下层节点,则给其补一个节点,如下图:

 2、中等算法题:两数相加_第3张图片

④、因为当前计算结果是14,需要进位,所以让L1下一个节点进位,如下图:

2、中等算法题:两数相加_第4张图片

⑤、重复②、③、④步骤,当结果如下图时:

 2、中等算法题:两数相加_第5张图片

则,L1和L2都没有后继节点,并且最后的节点之和等于10。此时,需要进位,因此新增一个节点,让L1最后一个节点指向新节点,如下图:

 2、中等算法题:两数相加_第6张图片

至此,【示例3】计算完成。如果是【示例1】那种标准的,最后不会产生进位的,则当两个链表没有后继节点时,即表示计算完成。

代码如下:

public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
    int c = l1.val + l2.val;
    l1.val = c % 10;

    if (l1.next == null && l2.next == null) {
        if (c > 9)
            l1.next = new ListNode(1);
        return l1;
    }

    if (l1.next == null) {
        l1.next = new ListNode(0);
    }

    if (l2.next == null) {
        l2.next = new ListNode(0);
    }

    if (c > 9) {
        l1.next.val++;
    }

    ListNode next = addTwoNumbers(l1.next, l2.next);
    l1.next = next;

    return l1;
}

 

测试代码:

/**
 * 反转ListNode链表
 * 
 * @param pre
 * @return
 */
public ListNode reverse(ListNode first) {
    ListNode pre = first;
    ListNode current = first.next;
    pre.next = null;
    while (current != null) {
        ListNode next = current.next;
        current.next = pre;
        pre = current;
        current = next;
    }

    return pre;
}

/**
 * 将一个整数转换为ListNode链表
 * 
 * @param n
 * @return
 */
public ListNode int2ListNode(int n) {
    ListNode node = new ListNode(n % 10);
    ListNode tmp = node;
    do {
        n = n / 10;
        if (n != 0) {
            ListNode next = new ListNode(n % 10);
            tmp.next = next;
            tmp = next;
        }
    } while (n != 0);

    return node;
}

public static void main(String[] args) {
    AddTwoNumbers atn = new AddTwoNumbers();
    ListNode l1 = atn.int2ListNode(876);
    ListNode l2 = atn.int2ListNode(132);
    ListNode result = atn.addTwoNumbers(l1, l2);
    ListNode first = atn.reverse(result);
    while (first != null) {
        System.out.print(first.val);
        first = first.next;
    }
}

 

运行结果:1008

当然,我们还可以测试更多组合,比如:l1=997、l2=7,l1=876、l2=232,l1=7、l2=7等,运行结果都是正确的。

 

这是我在leetcode上面的第二道题,感觉还是有一些难度的,对于我这种老年人来说(^ _ ^),这个代码在leetcode是提交成功的:

 

因此,应该是没问题的,毕竟经过了leetcode数据集的检验。

最近,空闲的时候在刷leetcode,感觉脑子都不够用了,加油锻炼思维~~

你可能感兴趣的:(算法)