LeetCode——2.Add Two Numbers

1.题目描述

原题链接:Add Two Numbers

You are given two non-empty linked lists representing two non-negative integers. 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(给你两个非空的链表,表示两个非负整数。这些整数是以逆着来存储的,而且链表中的每个节点都包含一个单位数。把这两个数字加起来然后以链表形式返回).

You may assume the two numbers do not contain any leading zero, except the number 0 itself(可以假设这两个数字不包含任何先导0,除了数字0以外).

Example:

Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 342 + 465 = 807.

然后完善下面的代码:

/**
 * 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) {
        
	}
};

2.解题思路

思路

两个链表上的数字是逆着表示的,但从HEAD开始正好是个位、十位、百位顺着下去,按小学学习的加法,将两数的同一数量级的单位数以及可能的进位加起来,然后用一个数字来存储进位,并将加起来的和模10,放入结果链表,就能解决这道题。

2.1 解法一

先是考虑用传入来的第一个链表存储结果,节省空间,如果空间不足,再用第二个链表,还是不足,就创建一个新的节点。这过程中,要用point将这些存储了结果的节点连接起来,作为结果链表。

class Solution {
public:
	ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
		ListNode head = ListNode(0);
		ListNode *point = &head;
		int carry = 0;
		while (l1 != NULL && l2 != NULL) {
			l1->val = carry + l1->val + l2->val;
			carry = l1->val / 10;
			l1->val = l1->val % 10;
			point->next = l1;
			l1 = l1->next;
			l2 = l2->next;
			point = point->next;
		}
		while (l1 != NULL) {
			l1->val = carry + l1->val;
			carry = l1->val / 10;
			l1->val = l1->val % 10;
			point->next = l1;
			l1 = l1->next;
			point = point->next;
		}
		while (l2 != NULL) {
			l2->val = carry + l2->val;
			carry = l2->val / 10;
			l2->val = l2->val % 10;
			point->next = l2;
			l2 = l2->next;
			point = point->next;
		}
		if (carry != 0)
			point->next = new ListNode(carry);
		return head.next;
	}
};

只是结果出人意料,竟然运行了68ms!我想着这应该是非常节省空间的了,除了最后的carry没有用第二个链表的节点来储存以外,但没有想到竟然这么耗时。我不管如何改进,还是这么个数值,甚至更差,所以可能不是什么思路的问题了,而是用多了成员访问符号"->"。

2.2 解法2

第二个方法,直接用简单粗暴的方法,不管什么空间复杂度了,不想着节省空间。只是在短的链表后面补0,用一个while将两个链表的对应节点相加,结果存储进一个全新的链表中。

class Solution {
public:
	ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode head = ListNode(0);
		ListNode *point = &head;
		int carry = 0;
		int sum = 0;
		while (l1 || l2) {
			sum = carry + (l1 ? l1->val : 0) + (l2 ? l2->val : 0);
			point->next = new ListNode(sum % 10);
			carry = sum / 10;
			if (l1) l1 = l1->next;
			if (l2) l2 = l2->next;
			point = point->next;
		}
		if (carry)
			point->next = new ListNode(carry);
		return head.next;
	}
};

结果是运行了44ms,看来成员访问符也是非常耗时的,用多了struct可能对性能影响很大,但这还不是终点,还可以继续优化。

2.3 解法3

if…else…、三目运算符之类的分支运算符最是消耗性能,所以能少用就尽量少用,而在上面我却在while循环里面用了两个三目运算符和两个if,显然这更是消耗性能,所以应该将它们摘出来,但这就无法处理较长的链表了,所以还得为第一个链表或者第二个链表还未遍历完的情况准备两个while,虽然多出了两个while,但实际上却是只要运行短链长度次数的一个while以及长链多余长度次数的另一个while而已,而这两个while都不需要条件分支了,而且第二个while只要考虑长链,所以整体来说,时间效率远比上面的高。至于其他情况,如并非一长一短的两条链,而是相同的链,那也只是运算一个while,且与上面相比还少了条件判断,所以性能更好。

class Solution {
public:
	ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode head = ListNode(0);
		ListNode *point = &head;
		int carry = 0;
		int sum = 0;
		while (l1 && l2) {
			sum = carry + l1->val + l2->val;
			point->next = new ListNode(sum % 10);
			carry = sum / 10;
			l1 = l1->next;
			l2 = l2->next;
			point = point->next;
		}
		while (l1) {
			sum = carry + l1->val;
			point->next = new ListNode(sum % 10);
			carry = sum / 10;
			l1 = l1->next;
			point = point->next;
		}
		while (l2) {
			sum = carry + l2->val;
			point->next = new ListNode(sum % 10);
			carry = sum / 10;
			l2 = l2->next;
			point = point->next;
		}
		if (carry)
			point->next = new ListNode(carry);
		return head.next;
	}
};

最终运行结果是28ms。

猜你喜欢

转载自blog.csdn.net/m0_37782473/article/details/82724233