Problem:Add Two Sum
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
Analysis
这一题属于单链表的题。实现的是单链表的相加,链表的每个元素是1-9的数字,两个数的长度不一定一样长,相加的时候注意进位的问题。
Solutions
两个链表list1,list2同时遍历,遍历的过程中,将两个链表的数相加,如果这个数小于10,直接赋值给list1中的的val,如果这个数大于10,将这个数取余赋值给list1中的val,再调用add函数,实现进位。最后判断list2的链表是不是还没有走完,如果没有走完,将list2链表的剩余部分给list1.
空间复杂度:
时间复杂度:
#python code
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
def add(l1): #发生进位的时候,使用递归调用。
lisk1 = l1
while lisk1.val >= 10:
lisk1.val = lisk1.val % 10
if lisk1.next == None:
lisk1.next = ListNode(1)
else:
lisk1.next.val += 1
lisk1.next = add(lisk1.next)
return l1
class Solution:
# @param {ListNode} l1
# @param {ListNode} l2
# @return {ListNode}
def addTwoNumbers(self, l1, l2):
lisk1, lisk2 = l1, l2
while lisk1 and lisk2: #当两个链表的next都不为空的时候
lisk1.val = lisk1.val + lisk2.val
if lisk1.val >= 10:
lisk1 = add(lisk1)
lisk3 = lisk1
lisk1, lisk2 = lisk1.next, lisk2.next
while(lisk2):
#如果l2不为空,l1的链表没有l2的长,将l2的后面链表加在l1的链表的后面
lisk3.next = lisk2
print lisk3.next.val
lisk2 = None
return l1
其他人的解法方案
//C++ code
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
long num1 = 0, num2 = 0, count = 0, sum = 0;
vector<int> nums;
while(l1) {
num1 = num1 + l1->val*pow(10,count);
l1 = l1->next;
count++;
}
count = 0;
while(l2) {
num2 = num2 + l2->val*pow(10,count);
l2 = l2->next;
count++;
}
sum = num1 + num2;
ListNode *ans = new ListNode(sum%10);
ListNode *cur = ans;
sum = sum / 10;
while(sum) {
cur->next = new ListNode(sum%10);
cur = cur->next;
sum /= 10;
}
return ans;
}
};
将链表表示的数,转换为数字相加,最后再将这个数构建成一个链表。(这个思路我也想到了,只是我没有实施,一直想法用单链表的形式来表示,这个给我一个提醒,以后看到题目的时候,将想到的思路全部写下来,然后在分析哪一个简单、高效、可行)
//C code
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) {
if(NULL == l1 || NULL == l2) {
return (NULL == l1) ? l2 : l1;
}
struct ListNode* result = NULL;
struct ListNode* head = NULL;
int sum = 0;
while(l1 != NULL || l2 != NULL || sum == 1){
int val = ((l1 == NULL) ? 0 : l1->val) + ((l2 == NULL) ? 0 : l2->val)+sum;
struct ListNode* tm = (struct ListNode*) malloc(sizeof(struct ListNode));
tm->next = NULL;
if(val >= 10){
tm->val = val % 10;
sum = 1;
}else{
tm->val = val;
sum = 0;
}
if(head == NULL){
head = tm;
}else{
result->next = tm;
}
result = tm;
if(l1 != NULL)l1 = l1->next;
if(l2 != NULL)l2 = l2->next;
}
return head;
}
遍历单链表,重新构建一个链表用来存放结果。而且这个链表的构建是反着构建的。比我的那个算法好的一个地方,就是使用了进位标志位(这个我也想到了,可是写的时候,没有想清楚,就放弃了),而我进位需要递归,效率上比不上,但是我的算法空间复杂度比这个要低一点(这个节省的有意义吗??)
//Java code
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode curNode = null;
ListNode prevNode = null;
ListNode nodeHead= null;
int carryOver = 0;
boolean first = true; // keep track of head of the sumNode chain
while (l1 !=null || l2 !=null){
int sum = ((l1!=null)?l1.val:0)+((l2!=null)?l2.val:0)+carryOver;
if (l1!=null)
l1 = l1.next;
if (l2!=null)
l2 = l2.next;
carryOver = sum /10;
sum = sum % 10;
curNode = new ListNode(sum);
if (first){
nodeHead = curNode;
first = false;
}else {
prevNode.next = curNode;
}
prevNode = curNode;
}
if (carryOver>0){
prevNode.next = new ListNode(carryOver);
}
return nodeHead;
}
这一段java代码的设计思想跟上一题差不多,不过可能由于Java效率的问题,时间上要久好多。
summarizes:
这一道题我犯的错误如下:
错误一:没有意识到进位(题目没有读懂,根据给的例子,应该自己用笔走一遍)
错误二:算法还没有完全想清楚就开始动手写代码,应该自己在纸上将算法走一遍,然后再来编写代码,这样快一些。
错误三:发现有例子没有符合算法的时候,使用if-else修补。如果只有几个特殊的点可以,但是如果这个点多了,就不是能够修复的了,这个是原来算法的设计的时候就有很大的问题,这个时候应该回去重新设计算法。
总结:配合给的例子将题意理解清楚,一定要自己动手走一遍,不能光靠脑子想。想算法的时候,如果在纸上不能走通,那么就不要动手编写代码。
Reference
《Python核心编程》