leetcode 第二题:链表的使用

题目大意:给定两个非空链表,分别代表两个非负整数。注意是以倒序的方式存储,并且一个节点存储一位数字。要求将这两个数相加,并将结果以链表的形式返回。

说明:这两个数均不包含前导的0,除非这个数就是0。

示例:输入链表:(2 -> 4 -> 3) 和链表(5 -> 6 -> 4),代表数字342与465求和,结果为807,输出形式:7 -> 0 -> 8,即倒序输出。

解题思路:刚读完题的第一想法很简单:既然是数相加,就直接读取链表,将对应的数赋给两个变量,再将其相加,最后将结果以倒序的方式输出就行了。但很快就意识到这样做并不好。一是题目没有交代数的大小,即使采用int64存储,仍然可能超范围,其次这是一道链表的题,应当用链表相关的知识去解决。

        随后我思考解决的方案。既然是相加,那就将对应位上的数相加,求模10解,有进位的话用标志位记录,加到下一位上。具体操作起来还有一些细节:一是两个数可能位数不一致,有的位上不能直接相加,需要先对缺失的位补0;其次是最后一位相加之后可能会向前再进一位,需要做特别处理。经过编写与本地调试之后,获得了AC。如下所示。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    int get_length(ListNode* l){
    int i;
	for(i=1;;i++)
		if(l->next!=NULL)
			l=l->next;
		else	
			return i;
    }
    ListNode* enhance(ListNode* l, int len){
    int t=len-get_length(l);
	if(t==0)
		return l;  //若本身足够长,则无需修改
	else
	{
		ListNode *p=l;
		while(p->next!=NULL)
		{
			p=p->next;
		}
		for(int i=0;i<t;i++)
		{
			p->next=new ListNode(0);
			p=p->next;
		}
		return l;
	}
    }
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
    int leng2,adder,flag;
	ListNode *res, head(0);
	leng2=max(get_length(l1),get_length(l2));
	enhance(l1,leng2);
	enhance(l2,leng2);
	flag=0;
	res=&head;  //用res记录头部节点
	for(int i=0;i<leng2;i++)  //对应位相加,赋给新建立的节点
	{
		adder=l1->val+l2->val+flag;
		res->next=new ListNode(adder%10);
		res=res->next;
		if(i!=leng2-1)
		{
			l1=l1->next;
			l2=l2->next;
		}
		flag=adder/10;
	}
	if(flag) res->next=new ListNode(1);  //表明要多一位
	else
		res->next=NULL;
	return head.next;  
    }
};      
       由于缺少经验,因此在书写代码时费了一番功夫。因为这是一道链表的小应用题,因此我并没有去专门的建立一个链表类,而是利用它给出的结构体定义进行了相关的操作。get_length()函数用于返回链表长度,enhance()函数用于将两链表扩充成一样的长度。最后在addTwoNumbers中将它们相加。这里,推荐创建一个头结点,然后通过一个指向其的指针对链表进行遍历等操作。

      不难发现 , 最后AC的代码比较冗长,而且在几处遍历了整个链表,比较耗时。在查看了discuss中的高票答案(如下)后,我发现了存在的几处提升空间:

ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) {
    ListNode preHead(0), *p = &preHead;
    int extra = 0;
    while (l1 || l2 || extra) {
        int sum = (l1 ? l1->val : 0) + (l2 ? l2->val : 0) + extra;
        extra = sum / 10;
        p->next = new ListNode(sum % 10);
        p = p->next;
        l1 = l1 ? l1->next : l1;
        l2 = l2 ? l2->next : l2;
    }
    return preHead.next;
}
     一是无需做复杂的填0操作,而是通过活用?:运算符,在两位相加时判断加数是否为空,如果是NULL,则认为其值是0即可 ;二是无需另外做高位进一处理,而是将循环结束条件修改为(l1 || l2 || extra)。这样一来,就大大减少了代码量,并且轻松获得AC。

     事实证明 ,一些小的处理能够大大简化代码的书写。在做题时,不妨多思考,再落笔。

  

              

猜你喜欢

转载自blog.csdn.net/xbb123456rt/article/details/77574274