题目:给定两个用链表表示的整数,每个结点包含一个数位。这些数位是反向存放的,也就是个位排在链表首部。编写函数对这两个整数求和,并用链表形式返回结果。
示例 输入:(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); }