本文转载自微信公众号「程序员小熊」,作者Dine。转载本文请联系程序员小熊公众号。
前言
大家好,我是来自于华为的程序员小熊。今天给大家带来一道各互联网大厂面试中常考的涉及到链表相关的中档题题,即力扣上的第 2 题-两数相加。
本文主要介绍迭代+虚拟头节点的策略来解答此题,供大家参考,希望对大家有所帮助。
两数相加
给你两个非空的链表,表示两个非负的整数。
它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储一位数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例1
其它示例及提示
解题思路
由于题目已明确告知每个节点只能存储一位数字,因此当两链表相同位置的数字之和大于 10 时,需要考虑进位的问题。
例两个链表:l1 = [3,4,3], l2 = [5,6,4]。
当他们的第二个节点的数字相加时,需要进位 1 到第三个节点的数字之和。
由于需要遍历一遍两个链表,所以考虑采用迭代的思想。
注意点
1.考虑中间位进位的问题;
例如 l1 = [3,4,3], l2 = [5,6,4]。
2.考虑最高位进位的问题。
例如 l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]。
举栗
以 l1 = [3,4,3], l2 = [5,6,4] 为例子,如下图示:
示例
不断遍历两个链表,将相同位置的节点的数值相加,并更新到新的链表;
相同位置的节点的数值相加并更新
遇到需要进位时,保留需要进位的值;
需要进位时,先保留进位
将上次进位的值与两链表本次节点的和相加;
进位更新
完整的处理过程,如下动图示:
两链表节点值相加更新到新链表,完整处理过程
Show me the Code
「C」
- struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){
- struct ListNode *dummyHead = (struct ListNode*)malloc(sizeof(struct ListNode));
- dummyHead->val = 0;
- dummyHead->next = NULL;
- struct ListNode *node = dummyHead;
- int carry = 0; // 进位
- /* 遍历两个链表 */
- for (struct ListNode* p = l1, *q = l2; p != NULL || q != NULL;) {
- /* 相同位置节点值之和 */
- int sum = carry;
- sum += (p != NULL) ? p->val : 0;
- sum += (q != NULL) ? q->val : 0;
- /* 将两链表相同位置的和的值,不断更新到新的链表 */
- node->next = (struct ListNode*)malloc(sizeof(struct ListNode));
- node = node->next;
- node->val = sum % 10;
- node->next = NULL;
- /* 进位处理,两链表不断遍历 */
- carry = sum / 10;
- p = (p == NULL) ? p : p->next;
- q = (q == NULL) ? q : q->next;
- }
- /* 最高位之和如果大于 10,增加一位,新链表的节点值为 1 */
- if(carry != 0) {
- node->next = (struct ListNode*)malloc(sizeof(struct ListNode));
- node = node->next;
- node->val = 1;
- node->next = NULL;
- }
- return dummyHead->next;
- }
「C++」
- ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
- ListNode* dummyHead = new ListNode(0);
- ListNode* node = dummyHead;
- int carry = 0;
- for (ListNode* p = l1, *q = l2; p != nullptr || q != nullptr;) {
- int sum = carry;
- sum += (p == nullptr) ? 0 : p->val;
- sum += (q == nullptr) ? 0 : q->val;
- node->next = new ListNode(sum % 10);
- node = node->next;
- carry = sum / 10;
- p = (p == nullptr) ? p : p->next;
- q = (q == nullptr) ? q : q->next;
- }
- if (carry != 0) {
- node->next = new ListNode(carry);
- }
- return dummyHead->next;
- }
「Java」
- ListNode addTwoNumbers(ListNode l1, ListNode l2) {
- ListNode dummyHead = new ListNode(-1);
- ListNode cur = dummyHead;
- int carry = 0;
- while (l1 != null || l2 != null) {
- int sum = carry;
- sum += (l1 == null) ? 0 : l1.val;
- sum += (l2 == null) ? 0 : l2.val;
- cur.next = new ListNode(sum % 10);
- cur = cur.next;
- carry = sum / 10;
- l1 = (l1 == null) ? l1 : l1.next;
- l2 = (l2 == null) ? l2 : l2.next;
- }
- if (carry != 0) {
- cur.next = new ListNode(carry);
- }
- return dummyHead.next;
- }
「Python3」
- def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
- dummyHead = ListNode(0)
- node = dummyHead
- carry = 0
- while(l1 or l2):
- sum = carry
- if(l1):
- sum += l1.val
- l1 = l1.next
- if l2:
- sum += l2.val
- l2 = l2.next
- node.next = ListNode(sum % 10)
- node = node.next
- carry = sum//10
- if carry != 0:
- node.next = ListNode(carry)
- return dummyHead.next
「Golang」
- func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {
- dummy := new(ListNode)
- node := dummy
- carry := 0
- for l1 != nil || l2 != nil {
- sum := carry
- if l1 != nil {
- sum += l1.Val
- l1 = l1.Next
- }
- if l2 != nil {
- sum += l2.Val
- l2 = l2.Next
- }
- node.Next = new(ListNode)
- node = node.Next
- node.Val = sum % 10
- carry = sum / 10
- }
- if carry != 0 {
- node.Next = &ListNode{Val: carry}
- }
- return dummy.Next
- }
复杂度分析
时间复杂度:O(max(m, n)),其中 m 和 n 分别为两个链表的长度,需要递归调用两个链表的每个节点一次。
空间复杂度:O(1),未开辟额外存储空间。