> 如果阅读时,发现错误,或者动画不可以显示的问题可以添加我微信好友 **[tan45du_one](https://raw.githubusercontent.com/tan45du/tan45du.github.io/master/个人微信.15egrcgqd94w.jpg)** ,备注 github + 题目 + 问题 向我反馈 > > 感谢支持,该仓库会一直维护,希望对各位有一丢丢帮助。 > > 另外希望手机阅读的同学可以来我的 [**公众号:袁厨的算法小屋**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png) 两个平台同步,想要和题友一起刷题,互相监督的同学,可以在我的小屋点击[**刷题小队**](https://raw.githubusercontent.com/tan45du/test/master/微信图片_20210320152235.2pthdebvh1c0.png)进入。 #### [面试题 02.05. 链表求和](https://leetcode-cn.com/problems/sum-lists-lcci/) 之前我们一起做了链表中的几个经典题型,找到倒数第 k 个节点,找链表中点,判断链表中环的起点,合并链表,反转链表,删除链表中重复值。这些是链表中的经典问题,面试中也经常会考的问题,然后下面我们继续做一道链表题目,也是面试中经常会考的题目,链表求和问题。 另外有一些小伙伴说,虽然一天一道题不算多,但是每天读题,做题加消化稍微有点跟不上,所以我打算每个周的工作日进行更新题目,到周末的时候对本周的题目进行总结,然后为大家再写一些别的东西。下面我们一起来看一下今天的题目吧。 > 为保证严谨性,所有文章中的代码都在网站进行验证,大家可以放心食用。 题目描述: 给定两个用链表表示的整数,每个节点包含一个数位。 这些数位是反向存放的,也就是个位排在链表首部。 编写函数对这两个整数求和,并用链表形式返回结果。 示例 1: ```java 输入:(7 -> 1 -> 6) + (5 -> 9 -> 2),即 617 + 295 输出:2 -> 1 -> 9,即 912 ``` 示例 2: ```java 输入:(9 -> 9) + (9 -> 9),即 99 + 99 输出:8 -> 9 -> 1 ``` 示例 3: ```java 输入:(5) + (5),即 5 + 5 输出:0 -> 1 ``` **题目解析:** 这个题目很容易理解,就是将链表数值进行求和,刚开始做题的同学可能会有这种思路,这个题目我们分别遍历两个链表得到他们的数,然后进行相加,再放到新的链表中,但是这样是行不通的, 因为我们需要考虑溢出的情况,java 中 int 型的范围为 -2147483648 到 +2147483648,即 -2^31 到 2^31。 所以链表比较长的话进行求和就会溢出,所以我们不能提取过之后再进行相加, 我们应该对链表的每一位进行相加,然后通过链表的和,判断是否需要像下一位进行传递, 就好比小时候我们用竖式进行加法一样,判断两位相加是否大于 10,大于 10 则进 1。 了解了思路,但是想完全实现代码也不是特别容易,这里需要注意的三个点就是, 1. 我们需要根据两个链表的长度,不断对新链表添加节点。 2. 需要创建一个变量用来保存进位值。 3. 当跳出循环之后,需要根据进位值来判断需不需要再对链表长度加 1。 这三条可以结合代码理解进行。 注:进位值只能是 0 或 1,因为每一位最大为 9,9+9=18; ![链表求和](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/链表求和.1yh4ymdee3k0.gif) 注:这里需要注意得时,链表遍历结束,我们应该跳出循环,但是我们的 nlist 仍在尾部添加了 1 节点,那是因为跳出循环时,summod 值为 1,所以我们需要在尾部再添加一个节点。 **题目代码** Java Code: ```java 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=1,9/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: ```cpp 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=1,9/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: ```js 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=1,9/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: ```python 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=1,9/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 # 去除哑节点 ``` Swift Code: ```swift class Solution { func addTwoNumbers(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? { var l1 = l1, l2 = l2 var nList = ListNode(-1) // 哑节点 var tempnode = nList // 用来保存进位值,初始化为0 var summod = 0 while l1 != nil || l2 != nil { // 链表的节点值 let l1num = l1?.val ?? 0 let l2num = l2?.val ?? 0 // 将链表的值和进位值相加,得到为返回链表的值 var sum = l1num + l2num + summod // 更新进位值,例18/10=1,9/10=0 summod = sum / 10 // 新节点保存的值,18%8=2,则添加2 sum = sum % 10 // 添加节点 tempnode.next = ListNode(sum) // 移动指针 tempnode = tempnode.next! if l1 != nil { l1 = l1?.next } if l2 != nil { l2 = l2?.next } } // 最后根据进位值判断需不需要继续添加节点 if (summod != 0) { tempnode.next = ListNode(summod) } return nList.next //去除哑节点 } } ``` Go Code: ```go func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode { root := &ListNode{} temp := root // 用来保存进位值,初始化为0 mod := 0 for (l1 != nil || l2 != nil) { l1num := 0 if l1 != nil { l1num = l1.Val } l2num := 0 if l2 != nil { l2num = l2.Val } // 将链表的值和进位值相加,得到为返回链表的值 sum := l1num + l2num + mod // 更新进位值,例18/10=1,9/10=0 mod = sum / 10 // 新节点保存的值,18%8=2,则添加2 sum = sum % 10 newNode := &ListNode{ Val: sum, } temp.Next = newNode temp = temp.Next if l1 != nil { l1 = l1.Next } if l2 != nil { l2 = l2.Next } } if mod != 0 { newNode := &ListNode{ Val: mod, } temp.Next = newNode } return root.Next } ```