Add Two Numbers LeetCode第二题

  • 题目描述:

You are given two linked lists representing two non-negative numbers. 
The digits are stored in reverse order and each of their nodes contain a single digit. 
Add the two numbers and return it as a linked list.

Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8

起初没看懂啥意思,后来百度了一下,又回过头看了一下题目描述,才知道题目是让干啥的了,也就是我上面标红的部分,其实这个题目是简化了的“大数相加”,从以下两个方面来降低了题目的难度:

  • 链表,每一个node中存储的是一位,可以直接使用
  • 给的链表是所要求和的书的倒序(reverse),即:2->4->3实际上所表示的是342,带上进位直接循环相加就行了

但是在处理的过程中,要注意以下问题:

  1. 两个链表的长度相同,并且相加所得的和的长度仍然不变,这是最简单的情形,记之为:ABC+DEF=GHI(注,这里的加数也是逆序的,与题目中描述的链表的形式是一致的,即ABC对应的真实的数据位CBA,下面没有特别说明的,都是按照这种形式),这种情况下,相加结束之后,即得到了最终的结果
  2. 两个链表的长度相同,但是相加所得的和的长度比原来的数的长度要长,这种情形较之刚才的稍微复杂一点,但还也不是特别复杂,记之为:ABC+DEF=GHIJ,这种情况下,相加结束之后,最终会剩余一个进位,这就需要在返回结果之前,还需要将进位添加到结果链表的尾部
  3. 两个链表的长度不同,这种情形下,又可以分出一下几种小情况:
  • 较短部分相加之后,没有向上的进位,将两个加数记为ABC和DEFG,即ABC和DEF相加完之后,没有往上的进位,此时只需要将剩余的F位添加到结果链表的末尾即可
  • 较短部分相加之后,有向上的进位,但是较长加数的剩余部分的第一位和进位相加后,没有再向上的后续进位,若将两个加数分别记为:AB和CDEF,即AB和CD向加之后,产生了一个向上的进位carry,此时CDEF中的E位要和carry相加,但是E和carry向加之后,没有进一步的进位,这种情况下,直接将E和carry相加的值重新赋值给E位,并将后续的位直接连接到结果链表中末尾就行了
  • 较短部分相加之后,有向上的进位,并且较长加数的剩余部分的第一位和进位相加后,又产生了后续的进位,这种进位关系,直到后边的某一位才结束,若将两个加数分别记为:AB和CDEFGHI,即AD和CD相加之后,产生了一个向上的进位carry,此时CDEFGHI中E为和carry相加之后又产生了新的进位,这种进位关系直到后边的某一位才结束,这种情况下,除了要将EFGHI添加到结果链表外,还行要按序执行和carry的相加,直到某位加完之后,不再产生进位

直接上代码,先上一个C++的

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode* pResultList = new ListNode(-1);
	    pResultList->next = NULL;
	    
        ListNode* p1 = l1;
    	ListNode* p2 = l2;
    	ListNode* pResultTailNode, *pResultNode;
    	int carry = 0, number = 0;		//记录进位信息和结果(指mod 10 之后)
    
    	//初始化resultList
    	pResultTailNode = pResultList;
    	pResultNode = NULL;
    
    	while(NULL != p1 && NULL != p2)
    	{
    		number = (p1->val + p2->val + carry) % 10;
    		carry = (p1->val + p2->val + carry) / 10;
    
    		pResultTailNode->next = new ListNode(number);
    		pResultTailNode = pResultTailNode->next;
    		pResultTailNode->next = NULL;
    		
    		p1 = p1->next;
    		p2 = p2->next;
    
    	}
    	
    	if (NULL != p1)
    	{
    		pResultTailNode->next = p1;
    		while(NULL != p1)
    		{
    			pResultTailNode = pResultTailNode->next;
    			number = (p1->val + carry) % 10;
    			carry = (p1->val + carry) / 10;
    			p1->val = number;
    			p1 = p1->next;
    		}
    	}
    
    	if (NULL != p2)
    	{
    		pResultTailNode->next = p2;
    		while(NULL != p2)
    		{
    			pResultTailNode = pResultTailNode->next;
    			number = (p2->val + carry) % 10;
    			carry = (p2->val + carry) / 10;
    			p2->val = number;
    			p2 = p2->next;
    		}
    	}
    
    	if (0 != carry)
    	{
    		pResultTailNode->next = new ListNode(carry);
    		pResultTailNode = pResultTailNode->next;
    		pResultTailNode->next = NULL;
    	}
    
    	pResultTailNode = pResultList->next;
    	delete pResultList;
    	pResultList = pResultTailNode;
    
    	return pResultList;
    }
};
该代码中,在相加完公共部分后,处理剩余部分的时候(即在if条件语句总的while判断条件处),只是在p1(或者p2)不为NULL为结束条件,不论carry是否为0,一直到结束,这会耗费时间,提交上之后,统计结果提示用了44ms

刚刚又修改了一下,只是在第41和第54行处的while循环条件上加了对carry的判断,因为当carry为0时,就不需要再往后遍历执行了,

        if (NULL != p1)
    	{
    		pResultTailNode->next = p1;
    		<span style="background-color: rgb(255, 0, 0);">while(NULL != p1 && 0 != carry)</span>
    		{
    			pResultTailNode = pResultTailNode->next;
    			number = (p1->val + carry) % 10;
    			carry = (p1->val + carry) / 10;
    			p1->val = number;
    			p1 = p1->next;
    		}
    	}
    
    	if (NULL != p2)
    	{
    		pResultTailNode->next = p2;
    		<span style="background-color: rgb(255, 0, 0);">while(NULL != p2 && 0 != carry)</span>
    		{
    			pResultTailNode = pResultTailNode->next;
    			number = (p2->val + carry) % 10;
    			carry = (p2->val + carry) / 10;
    			p2->val = number;
    			p2 = p2->next;
    		}
    	}
这时,又看了下Details,发现运行时间减少了8ms,但是距离C++代码中的最优代码,还有一点点差距,

后来又写了一个C版本的,与C++版本的相比,执行时间要减少了一半,直接贴代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) {
        
        struct ListNode* pResultList = (struct ListNode*)malloc(sizeof(struct ListNode));
	    pResultList->next = NULL;
	    
        struct ListNode* p1 = l1;
    	struct ListNode* p2 = l2;
    	struct ListNode* pResultTailNode, *pResultNode;
    	int carry = 0, number = 0;		//记录进位信息和结果(指mod 10 之后)
    
    	//初始化resultList
    	pResultTailNode = pResultList;
    	pResultNode = NULL;
    
    	while(NULL != p1 && NULL != p2)
    	{
    		number = (p1->val + p2->val + carry) % 10;
    		carry = (p1->val + p2->val + carry) / 10;
    
    		pResultTailNode->next = (struct ListNode *)malloc(sizeof(struct ListNode));
    		pResultTailNode = pResultTailNode->next;
    		pResultTailNode->val = number;
    		pResultTailNode->next = NULL;
    		
    		p1 = p1->next;
    		p2 = p2->next;
    
    	}
    	
    	if (NULL != p1)
    	{
    		pResultTailNode->next = p1;
    		while(NULL != p1)
    		{
    			pResultTailNode = pResultTailNode->next;
    			number = (p1->val + carry) % 10;
    			carry = (p1->val + carry) / 10;
    			p1->val = number;
    			p1 = p1->next;
    		}
    	}
    
    	if (NULL != p2)
    	{
    		pResultTailNode->next = p2;
    		while(NULL != p2)
    		{
    			pResultTailNode = pResultTailNode->next;
    			number = (p2->val + carry) % 10;
    			carry = (p2->val + carry) / 10;
    			p2->val = number;
    			p2 = p2->next;
    		}
    	}
    
    	if (0 != carry)
    	{
    		pResultTailNode->next = (struct ListNode *)malloc(sizeof(struct ListNode));
    		pResultTailNode = pResultTailNode->next;
    		pResultTailNode->val = carry;
    		pResultTailNode->next = NULL;
    	}
    
    	pResultTailNode = pResultList->next;
    	free(pResultList);
    	pResultList = pResultTailNode;
    
    	return pResultList;
}

与C++版本的类似,在while循环中,如果加上对carry的判断,执行时间会减少2ms,

        if (NULL != p1)
    	{
    		pResultTailNode->next = p1;
    		while(NULL != p1 && 0 != carry)
    		{
    			pResultTailNode = pResultTailNode->next;
    			number = (p1->val + carry) % 10;
    			carry = (p1->val + carry) / 10;
    			p1->val = number;
    			p1 = p1->next;
    		}
    	}
    
    	if (NULL != p2)
    	{
    		pResultTailNode->next = p2;
    		while(NULL != p2 && 0 != carry)
    		{
    			pResultTailNode = pResultTailNode->next;
    			number = (p2->val + carry) % 10;
    			carry = (p2->val + carry) / 10;
    			p2->val = number;
    			p2 = p2->next;
    		}
    	}
details

注:关于代码最后的三句:

        pResultTailNode = pResultList->next;
    	delete pResultList;
    	pResultList = pResultTailNode;
至于为何要添加这三句,链表有带头结点的链表和不带头结点的链表,而此处我是将其看做不带头结点的链表来处理的。

有更近一步优化的,还望进一步交流~~大笑大笑大笑


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值