LeetCode 2.add Two Numbers (C语言)
这里直接截图来看了。
大致意思是给两个链表,将链表的各个对应位置的数字加起来得出一个新的链表。其实这是一个计算器的加法操作的实现。计算器接收输入时,它是一个数字一个数字接收的,所以250这个数字,接收到的是单独的2,5和0这几个数。上图的(2->4->3) + (5->6->4) = (7->0->8)其实看成数字就是342+465=807。 在计算器中,用户输入数字342是先输入一个3,再一个4,再一个2。这个输入的三个数就是上边的链表2->4->3的存放过程,在链表后边追加数字就行了。 而后续计算加法时,刚好是从个位开始计算,也就是链表的第一个。 所以整体弄下来,这个题最主要是解决进位的问题。
我们看下solution里边的提示发现几个比较特殊的用例需要我们考虑。
所以这个题我们可以先考虑最简单的情况[1] + [2]这种简单列表,通过测试后再考虑多个数的情况;然后再考虑两个列表长度不一样的情况;然后再考虑有进位的情况;然后再考虑不一样长度还会进位的情况。
贴下我的代码,不是最优的。不过看了下最优的那个(25ms),思路基本是一样的,只是调整了代码结构。然后多了个思路,即如果两个链表不一样长,就让短的那个后边的全部都为0,让两个列表长度一样长。 有兴趣的可以去官网看下最低用时的那个算法的源码。
(我代码里把/和%运算符换成加减运算,貌似时间没有变化。要改成位运算估计才会有点优化的效果。里边大量注释是我自己看的,请忽略之。)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) {
struct ListNode* retHead = NULL;//这个是用来返回的节点指针
if(l1 != NULL && l2 != NULL){
struct ListNode* lastNode = NULL; //要返回的列表的最后一个节点
struct ListNode* tempNode = NULL; //用来存放求出来的每一位的数字的新节点
int addPromote = 0;//两个数字相加后需要进位的数字,一般是1或0
int autoPromote = 0; //求出的数自己加上之前的进位,自己为0自动又进一位
struct ListNode* node1 = l1;
struct ListNode* node2 = l2;
//1.这个是计算两个列表共有的节点个数的数字
while(node1 != NULL && node2 != NULL){
autoPromote = 0;
int val1 = node1->val;
int val2 = node2->val;
tempNode = (struct ListNode*)malloc(sizeof(struct ListNode)); //先构造一个存放的节点
tempNode->next = NULL; //这个一定要初始化,不然会报错
if(retHead == NULL)//保存一下用来返回的头指针
retHead = tempNode;
int sum = val1 + val2;
//int left = (val1 + val2) % 10;//求余得到此位置的数据
int left = sum <= 9 ? sum:sum - 10;
int now = left + addPromote; //当前位置上的数字
//autoPromote = now / 10;//有可能当前位置上的数字加上上次的进位刚好又到了10,则下一位还需要进位一下
//tempNode->val = now % 10; //求余才是正确的数字,直接赋值now有可能就是10. [9,8,9] [1,2]
autoPromote = now <= 9 ? 0 : 1;
tempNode->val = now <= 9 ? now : now - 10;
if(lastNode != NULL)//表明不是第一次进来
lastNode->next = tempNode;//添加到最后
lastNode = tempNode;//指向最后一个
//下次进来需要的数据
//addPromote = (val1 + val2 + autoPromote) / 10;//进位的数字,
addPromote = (sum + autoPromote) <= 9 ? 0 : 1;//进位的数字,
node1 = node1->next;
node2 = node2->next;
}
//2.从这里开始,表明某一个节点数字加完了,另外一个节点可能还有数字;[9,9,9,9] [2,1]
struct ListNode* leftNode = node1 != NULL ? node1 : node2;
if(leftNode != NULL){ //剩下的这个列表,唯一还可以加的数字就是之前第一步算完可能有的一个进位了
lastNode->next = leftNode; //把最后多余的部分拼上去
while(leftNode != NULL && addPromote > 0){ //如果后边还会自动进位的话还需要遍历算
lastNode = leftNode;
int now = leftNode->val + addPromote;
//addPromote = now / 10;
//leftNode->val = now % 10;
addPromote = now <= 9 ? 0 : 1;
leftNode->val = now <= 9 ? now : now - 10;
leftNode = leftNode->next;
}
}
if(addPromote > 0){ //最高位在进位之后自动大于了10,所以还要进位一次
tempNode = (struct ListNode*)malloc(sizeof(struct ListNode)); //先构造一个存放的节点
tempNode->next = NULL;
tempNode->val = addPromote;//进位数据
lastNode->next = tempNode;
}
}
return retHead;
}