题目:给定两个用链表表示的整数,每个结点包含一个数位。这些数位是反向存放的,也就是个位排在链表首部。编写函数对这两个整数求和,并用链表形式返回结果。
示例 输入:(7->1->6) +(5->9->2),即617+295
输出:2->1->9,即912。
进阶 假设这些数位是正向存放的,请再做一遍。
示例 输入:(6->1->7) + (2->9->5),即617+295.
输出:9->1->2,即912。
先考虑前一个问题,由于链表是从低位开始的,所以可以直接相加保存进位。但是需要注意两个链表的长度可能不相等。如果不使用额外的内存空间,可以把结果保存在较长的链表中,如果确定保存在第一个链表中,那么需要记录上一次相加的结点。因为当第一个链表已经走完而第二个链表还没有结束时,可以将第一个链表的上一个结点(即最后一个结点)指向第二个链表,后面的相加结果保存在第二个链表中。
ListNode* ListAdd(ListNode* pHead1, ListNode* pHead2)
{
if(pHead1 == NULL)
return pHead2;
if(pHead2 == NULL)
return pHead1;
int carry = 0;
ListNode* node1, *ListEnd;
node1 = ListEnd = pHead1;
ListNode* node2 = pHead2;
while(node1 != NULL || node2 != NULL)
{
if(node1 != NULL && node2 != NULL)
{
node1->m_nValue = node1->m_nValue + node2->m_nValue + carry;
if(node1->m_nValue >= 10)
{
node1->m_nValue = node1->m_nValue - 10;
carry = 1;
}
else
carry = 0;
ListEnd = node1;
node1 = node1->m_pNext;
node2 = node2->m_pNext;
}
else
{
if(node1 == NULL)
{
ListEnd->m_pNext = node2;
node2->m_nValue = node2->m_nValue + carry;
if(node2->m_nValue >= 10)
{
node2->m_nValue = node2->m_nValue - 10;
carry = 1;
}
else
carry = 0;
ListEnd = node2;
node2 = node2->m_pNext;
}
else
{
node1->m_nValue = node1->m_nValue + carry;
if(node1->m_nValue >= 10)
{
node2->m_nValue = node1->m_nValue - 10;
carry = 1;
}
else
carry = 0;
ListEnd = node1;
node1 = node1->m_pNext;
}
}
}
if(carry != 0)
{
ListNode* End = CreateListNode(carry);
ListEnd->m_pNext = End;
}
return pHead1;
}
可以看到上面的方法实在过于繁琐,不使用辅助空间而且不用递归就得在代码复杂度上做出牺牲,下面利用递归并且允许新建链表保存结果的情况下,代码精简很多。
<span style="font-size:10px;">ListNode* AddCore(ListNode* node1, ListNode* node2, int carry)
{
if(node1 == NULL && node2 == NULL && carry == 0)
return NULL;
ListNode* result = CreateListNode(0);
int value = carry;
if(node1 != NULL)
value += node1->m_nValue;
if(node2 != NULL)
value += node2->m_nValue;
result->m_nValue = value % 10;
ListNode* nextNode = AddCore(node1==NULL?NULL:node1->m_pNext, node2==NULL?NULL:node2->m_pNext, value>=10?1:0);
result->m_pNext = nextNode;
return result;
}
ListNode* ListAdd(ListNode* pHead1, ListNode* pHead2)
{
return AddCore(pHead1, pHead2, 0);
}</span>
下面分析第二个问题,由于第二个问题中的链表只是前面问题中的链表的反序,因此可以将链表反转,利用前面的算法,最后求得的结果仍然是反序的,再反转结果,最后就是问题的正向解。
ListNode* AddCore(ListNode* node1, ListNode* node2, int carry)
{
if(node1 == NULL && node2 == NULL && carry == 0)
return NULL;
ListNode* result = CreateListNode(0);
int value = carry;
if(node1 != NULL)
value += node1->m_nValue;
if(node2 != NULL)
value += node2->m_nValue;
result->m_nValue = value % 10;
ListNode* nextNode = AddCore(node1==NULL?NULL:node1->m_pNext, node2==NULL?NULL:node2->m_pNext, value>=10?1:0);
result->m_pNext = nextNode;
return result;
}
ListNode* ReverseListAdd(ListNode* pHead1, ListNode* pHead2)
{
return AddCore(pHead1, pHead2, 0);
}
ListNode* ReverseList(ListNode* pHead)
{
if(pHead == NULL || pHead->m_pNext == NULL)
return pHead;
ListNode* prev = NULL;
ListNode* curr = pHead;
while(curr != NULL)
{
ListNode* next = curr->m_pNext;
curr->m_pNext = prev;
prev = curr;
curr = next;
}
return prev;
}
ListNode* ForwardListAdd(ListNode* pHead1, ListNode* pHead2)
{
if(pHead1 == NULL)
return pHead2;
if(pHead2 == NULL)
return pHead1;
return ReverseList(ReverseListAdd(ReverseList(pHead1), ReverseList(pHead2)));
}
如果不利用前面一问的结果,正向的链表相加也是可以解的。从链表的前面结点开始相加,由于前面结点代表高位,它需要低位结点相加的进位,但是低位结点不可能先于高位结点访问到,这时候就需要用递归的办法了,通过递归嵌套出低位来额进位,实际上还是从低位开始先加。同样需要注意链表不等长的问题,如果直接从高位往低位递归,就出现了错位问题,譬如不同表长的两个链表首结点代表的权值是不同的,不应该由他们俩相加。这是后可以考虑在较短链表的前面补零的办法,使两个链表等长。
int AddNodes(ListNode* node1, ListNode* node2)
{
if(node1->m_pNext == NULL && node2->m_pNext == NULL)
node1->m_nValue = node1->m_nValue + node2->m_nValue;
else
node1->m_nValue = node1->m_nValue + node2->m_nValue + AddNodes(node1->m_pNext, node2->m_pNext);
if(node1->m_nValue >= 10)
{
node1->m_nValue = node1->m_nValue - 10;
return 1;
}
else
return 0;
}
ListNode* AddCore(ListNode* pHead1, ListNode* pHead2)
{
if(AddNodes(pHead1, pHead2) == 1)
{
ListNode* newHead = CreateListNode(1);
newHead->m_pNext = pHead1;
return newHead;
}
else
return pHead1;
}
ListNode* ForwardListAdd(ListNode** pHead1, ListNode** pHead2)
{
if(pHead1 == NULL || pHead2 == NULL)
return NULL;
if(*pHead1 == NULL)
return *pHead2;
if(*pHead2 == NULL)
return *pHead1;
//短链表补零
int size1, size2;
size1 = size2 = 0;
for(ListNode* node1 = *pHead1; node1 != NULL; node1 = node1->m_pNext,++size1);
for(ListNode* node2 = *pHead2; node2 != NULL; node2 = node2->m_pNext,++size2);
if(size1 != size2)
{
for(int i = 0; i < abs(size1 - size2); ++i)
{
ListNode* newHead = CreateListNode(0);
if(size1 < size2)
{
newHead->m_pNext = *pHead1;
*pHead1 = newHead;
}
else
{
newHead->m_pNext = *pHead2;
*pHead2 = newHead;
}
}
}
return AddCore(*pHead1, *pHead2);
}