algorithm-base/animation-simulation/链表篇/面试题 02.05. 链表求和.md
2021-07-16 00:06:52 +08:00

9.0 KiB
Raw Blame History

如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 tan45du_one ,备注 github + 题目 + 问题 向我反馈

感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。

另外希望手机阅读的同学可以来我的 公众号:袁厨的算法小屋 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击刷题小队进入。

面试题 02.05. 链表求和

之前我们一起做了链表中的几个经典题型找到倒数第k个节点找链表中点判断链表中环的起点合并链表反转链表删除链表中重复值。这些是链表中的经典问题面试中也经常会考的问题然后下面我们继续做一道链表题目也是面试中经常会考的题目链表求和问题。

另外有一些小伙伴说,虽然一天一道题不算多,但是每天读题,做题加消化稍微有点跟不上,所以我打算每个周的工作日进行更新题目,到周末的时候对本周的题目进行总结,然后为大家再写一些别的东西。下面我们一起来看一下今天的题目吧。

为保证严谨性,所有文章中的代码都在网站进行验证,大家可以放心食用。

题目描述:

给定两个用链表表示的整数,每个节点包含一个数位。

这些数位是反向存放的,也就是个位排在链表首部。

编写函数对这两个整数求和,并用链表形式返回结果。

示例1

输入(7 -> 1 -> 6) + (5 -> 9 -> 2) 617 + 295
输出2 -> 1 -> 9 912

示例2

输入(9 -> 9) + (9 -> 9) 99 + 99
输出8 -> 9 -> 1

示例3

输入(5) + (5) 5 + 5
输出0 -> 1

题目解析:

这个题目很容易理解,就是将链表数值进行求和,刚开始做题的同学可能会有这种思路,这个题目我们分别遍历两个链表得到他们的数,然后进行相加,再放到新的链表中,但是这样是行不通的,

因为我们需要考虑溢出的情况java 中 int 型的范围为 -2147483648 到 +2147483648即 -2^31 到 2^31。

所以链表比较长的话进行求和就会溢出,所以我们不能提取过之后再进行相加,

我们应该对链表的每一位进行相加,然后通过链表的和,判断是否需要像下一位进行传递,

就好比小时候我们用竖式进行加法一样判断两位相加是否大于10大于10则进1。

了解了思路,但是想完全实现代码也不是特别容易,这里需要注意的三个点就是,

  1. 我们需要根据两个链表的长度,不断对新链表添加节点。

  2. 需要创建一个变量用来保存进位值。

  3. 当跳出循环之后需要根据进位值来判断需不需要再对链表长度加1。

这三条可以结合代码理解进行。

进位值只能是0或1因为每一位最大为99+9=18

链表求和

注:这里需要注意得时,链表遍历结束,我们应该跳出循环,但是我们的 nlist 仍在尾部添加了1节点那是因为跳出循环时summod 值为1所以我们需要在尾部再添加一个节点。

题目代码

Java Code:

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
         //待会儿要返回的链表
         ListNode nList = new ListNode(-1);//哑节点
         ListNode tempnode = nList;
         //用来保存进位值初始化为0
         int summod = 0;
         while(l1 != null || l2 != null) {
             //如果l1的链表为空则l1num为0若是不为空则为链表的节点值
             //判断是否为空为空就设为0
             int l1num = l1 == null ? 0 : l1.val;
             int l2num = l2 == null ? 0 : l2.val;
             //将链表的值和进位值相加,得到为返回链表的值
             int sum = l1num+l2num+summod;
             //更新进位值例18/10=19/10=0
             summod = sum/10;
             //新节点保存的值18%8=2则添加2
             sum = sum%10; 
             //添加节点
             tempnode.next = new ListNode(sum);
             //移动指针
             tempnode = tempnode.next;
             if (l1 != null) {
                 l1 = l1.next;
             }
             if (l2 != null) {
                 l2 = l2.next;
             }            
         }
         //最后根据进位值判断需不需要继续添加节点
         if (summod != 0) {
             tempnode.next = new ListNode(summod);
         }
         return nList.next;//去除哑节点
    }
}

C++ Code:

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
         //待会儿要返回的链表
         ListNode * nList = new ListNode(-1);//哑节点
         ListNode * tempnode = nList;
         //用来保存进位值初始化为0
         int summod = 0;
         while(l1 != nullptr || l2 != nullptr) {
             //如果l1的链表为空则l1num为0若是不为空则为链表的节点值
             //判断是否为空为空就设为0
             int l1num = l1 == nullptr ? 0 : l1->val;
             int l2num = l2 == nullptr ? 0 : l2->val;
             //将链表的值和进位值相加,得到为返回链表的值
             int sum = l1num + l2num + summod;
             //更新进位值例18/10=19/10=0
             summod = sum / 10;
             //新节点保存的值18%8=2则添加2
             sum = sum % 10; 
             //添加节点
             tempnode->next = new ListNode(sum);
             //移动指针
             tempnode = tempnode->next;
             if (l1 != nullptr) {
                 l1 = l1->next;
             }
             if (l2 != nullptr) {
                 l2 = l2->next;
             }            
         }
         //最后根据进位值判断需不需要继续添加节点
         if (summod != 0) {
             tempnode->next = new ListNode(summod);
         }
         return nList->next;//哑节点
    }
};

JS Code:

var addTwoNumbers = function(l1, l2) {
    //待会儿要返回的链表
    let nList = new ListNode(-1);//哑节点
    let tempnode = nList;
    //用来保存进位值初始化为0
    let summod = 0;
    while (l1 || l2) {
        //如果l1的链表为空则l1num为0若是不为空则为链表的节点值
        //判断是否为空为空就设为0
        let l1num = l1 === null ? 0 : l1.val;
        let l2num = l2 === null ? 0 : l2.val;
        //将链表的值和进位值相加,得到为返回链表的值
        let sum = l1num + l2num + summod;
        //更新进位值例18/10=19/10=0
        summod = ~~(sum / 10);
        //新节点保存的值18%8=2则添加2
        sum = sum % 10;
        //添加节点
        tempnode.next = new ListNode(sum);
        //移动指针
        tempnode = tempnode.next;
        if (l1) {
            l1 = l1.next;
        }
        if (l2) {
            l2 = l2.next;
        }
    }
    //最后根据进位值判断需不需要继续添加节点
    if (summod !== 0) {
        tempnode.next = new ListNode(summod);
    }
    return nList.next;//去除哑节点
};

Python Code:

class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        # 待会儿要返回的链表
        nList = ListNode(-1)  # 哑节点
        tempnode = nList
        # 用来保存进位值初始化为0
        summod = 0
        while l1 is not None o l2 is not None:
            # 如果l1的链表为空则l1num为0若是不为空则为链表的节点值
            # 判断是否为空为空就设为0
            l1num = 0 if l1 is None else l1.val
            l2num = 0 if l2 is None else l2.val
            # 将链表的值和进位值相加,得到为返回链表的值
            sum_ = l1num + l2num + summod
            # 更新进位值例18/10=19/10=0
            # 新节点保存的值1 %8=2则添加2
            # 注这里使用divmod函数对上方的代码进行了一丢丢的简化
            summod, sum_ = divmod(sum_, 10)
            # 添加节点
            tempnode.next = ListNode(sum_)
            # 移动指针
            tempnode = tempnode.next
            if l1 is not None:
                l1 = l1.next
            if l2 is not None:
                l2 = l2.next
        # 最后根据进位值判断需不需要继续添加节点
        if summod != 0:
            tempnode.next = ListNode(summod)
        return nList.next  # 去除哑节点