算法设计周记(一)--大数加法

绪论:

值大三开学之际,选修算法分析与设计一课,开启博客记录下自己的学习足迹,以期于过程中加深心得

问题导入:

本系列所选题目皆来自于LeetCode网站,首先尝试的是以小端模式单向链表存储的大数加法,问题描述如下 算法设计周记(一)--大数加法_第1张图片
数据类型以及接口已经定义好
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {}
};

解法分析:

链表非空,数字非负,小端模式存储也很符合加法从低位开始的竖式计算。直接new出一个ListNode实例,记录下地址用于返回,从最低位起逐个相加并存储结果
        ListNode* rst = new ListNode(0);
        ListNode* rtn = rst;
        while (l1->next != NULL && l2->next != NULL) {
            rst->val = rst->val + l1->val + l2->val;
            int digit = rst->val/10;
            rst->val %= 10;
            rst->next = new ListNode(digit);
            rst = rst->next;
            l1 = l1->next;
            l2 = l2->next;
        }
这里特意留出最高位用于之后的进位处理。考虑到两个加数的位数可能不相等,最高位有无进位对之后的操作有一定影响,故而进行了分类讨论
        rst->val = rst->val + l1->val + l2->val;
        if (rst->val > 9) {
            rst->val %= 10;
            rst->next = new ListNode(1);
            rst = rst->next;
            l1 = l1->next;
            l2 = l2->next;
            if (l1 != NULL || l2 != NULL) {
                ListNode* over = (l1 == NULL)? l2 : l1;
                while (over->next != NULL) {
                    rst->val += over->val;
                    int dgt = rst->val/10;
                    rst->val %= 10;
                    rst->next = new ListNode(dgt);
                    rst = rst->next;
                    over = over->next; 
                }
                rst->val += over->val;
                if (rst->val > 9) {
                    rst->val %= 10;
                    rst->next = new ListNode(1);
                }
            }
        } else {
            l1 = l1->next;
            l2 = l2->next;
            if (l1 != NULL || l2 != NULL) {
                ListNode* over = (l1 == NULL)? l2 : l1;
                while (over != NULL) {
                    rst->next = new ListNode(0);
                    rst = rst->next;
                    rst->val += over->val;
                    over = over->next; 
                }
            }
        }
最后将首地址rtn返回即可


探究升华:

题目看似不难,但若在进位操作中未考虑到所有可能的情形,极容易出现谬误。同时也是局限于我的思考框架,代码看起来有些冗长。为此我fork一份比较优秀的solution以供学习参考
ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) {
    ListNode preHead(0), *p = &preHead;
    int extra = 0;
    while (l1 || l2 || extra) {
        int sum = (l1 ? l1->val : 0) + (l2 ? l2->val : 0) + extra;
        extra = sum / 10;
        p->next = new ListNode(sum % 10);
        p = p->next;
        l1 = l1 ? l1->next : l1;
        l2 = l2 ? l2->next : l2;
    }
    return preHead.next;
}
该解法设置了数值为0的头结点,运用到了计算机二进制加法器中的sum位和carry位,?表达式的灵活运用使得代码整体十分简洁有力。

你可能感兴趣的:(算法设计周记(一)--大数加法)