每日一题
两个链表相加
思考历程(错误解法)
看到这题,我首先想到的就是直接正序相加。
首先创建一个新表头,并让其数据域为零。
要进行正序相加,就必须保证两个链表所代表数字的个、十、百·······位对齐,因此我们就必须计算这连个链表的长度,和他们的长度差,再定义两个指针变量cur1、cur2,使其分别指向表一表二的头,最后让链表较长的cur走count个节点,同时将这些节点的数据域链接到新表(需要新建节点)。
当cur1和cur2对齐后,就可以进行逐位相加了,如果相加的值大于等于10,就向前一位进一 。
做到这里,突然就发现不对了。如果我们只需要进一位,如 5 -> 4 -> 9 这种情况,我们只需要定义一个pre保存前一个节点即可,但如果我们要进位多位,如 5 -> 9 -> 9 -> 9 这种情况,显然这种方法是行不通的。
思路
- 既然正序相加不行,那我们是否可以考虑逆序相加。
- 单向链表不能从后往前遍历,所以,我们首先应该反转两个单链表(反转单链表的操作)。
- 反转过后,显然我们可以发现,两个链表所代表数字的个位、十位、百位······都依次对齐,这样我们就可以直接相加,最后将新链表翻转返回即可。
步骤
- 翻转两个已知链表。
- 创建新表头,定义指针变量cur1、cur2、cur3,使其分别指向三个链表的头
- 定义进位标志flag,如果其为1,就需进位,为0则不需进位
- 在循环中,创建新节点,其数据域为,(cur1->val + cur2->val + flag) % 10,之后再更新flag,flag = (cur1->val + cur2->val + flag) / 10,最后再让cur1,cur2下滑一个节点
- 只要cur1、cur2、flag有一个不为假,就说明还没有相加完毕,继续循环
- 最后,返回新表头的next(新表头没有有效数据)
实现代码
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
/**
*
* @param head1 ListNode类
* @param head2 ListNode类
* @return ListNode类
*/
struct ListNode* FilpLinkList(struct ListNode* phead) //反转链表
{
if(!phead)
return NULL;
struct ListNode* newHead = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* cur = phead;
newHead->next = phead;
while(cur->next)
{
struct ListNode* temp = cur->next;
cur->next = temp->next;
temp->next = newHead->next;
newHead->next = temp;
}
return newHead->next;
}
struct ListNode* CreatNewNode(int num) //创建新节点
{
struct ListNode* newNode = (struct ListNode *)malloc(sizeof(struct ListNode));
newNode->next = NULL;
newNode->val = num;
return newNode;
}
struct ListNode* addInList(struct ListNode* head1, struct ListNode* head2 ) {
if(head1 == NULL || head2 == NULL) //只要head1、head2有一个为空,就相当于加数为0,直接返回不为空的表头,两个都为空,同理。
return head1 == NULL ? head2 : head1;
struct ListNode* head3 = (struct ListNode*)malloc(sizeof(struct ListNode)); //新建表头
//反转链表
head1 = FilpLinkList(head1);
head2 = FilpLinkList(head2);
struct ListNode* cur1 = head1, *cur2 = head2,*cur3 = head3;
int flag = 0,val1,val2;
while(cur1 || cur2 || flag)
{
//如果cur为空,说明已经走到表尾,直接令val为0即可
val1 = cur1 == NULL ? 0 : cur1->val;
val2 = cur2 == NULL ? 0 : cur2->val;
cur3->next = CreatNewNode((val1 + val2 + flag) % 10); //创建新节点
flag = (val1 + val2 + flag) / 10; //更新flag
cur3 =cur3->next;
//如果cur为空,则停止下滑
cur1 = cur1 == NULL ? NULL : cur1->next;
cur2 = cur2 == NULL ? NULL : cur2->next;
}
return FilpLinkList(head3->next); //翻转新表
}