C语言程序设计整理(8)两数相加

(一)问题描述

       给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。请你将两个数相加,并以相同形式返回一个表示和的链表。你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

(二)示例展示

输入:l1 = [2, 4, 3];l2 = [5, 6, 4]

输出:[7, 0, 8]

解释:342 + 465 = 807

(三)算法分析

        首先,整体过程是一个加法运算。其次,具体的实现方式是使用链表来完成,从而避免了 int 类型大小有限的缺陷。最后,输出的是一个链表的头。因此,解答的过程主要包括:遍历链表,创建新链表,两数按位相加并判断是否进位。为了方便起见,我们使用尾插法来创建链表,下面的参考代码将给出两种方法解决此问题。

(四)参考代码

        说明一下:原题来自 LeetCode ,题目的要求是按照一定的函数结构进行编写,给出的函数参数是两个被加数的头,并且给出了结构体的形式如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

1、4ms 版本,非常简洁,使用了三元表达式非常聪明!

struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) {
    struct ListNode* head = NULL; // 新链表的头节点
    struct ListNode* tail = NULL; // 新链表的尾节点
    int carry = 0; // 进位
    while (l1 != NULL || l2 != NULL) { // 当两个链表只要有一个没有遍历完时,循环就继续
        int val1 = l1 != NULL ? l1->val : 0; // 如果 l1 不为空,取其节点值,否则为 0
        int val2 = l2 != NULL ? l2->val : 0; // 如果 l2 不为空,取其节点值,否则为 0
        int sum = val1 + val2 + carry; // 计算两个节点值和进位的和
        carry = sum / 10; // 更新进位
        struct ListNode* node = (struct ListNode*)malloc(sizeof(struct ListNode)); // 创建新的节点
        node->val = sum % 10; // 节点值为和的个位数
        node->next = NULL; // 节点指针为 NULL
        if (head == NULL) { // 如果新链表为空,将头节点和尾节点都指向新节点
            head = node;
            tail = node;
        } else { // 如果新链表不为空,将尾节点的指针指向新节点,并更新尾节点
            tail->next = node;
            tail = node;
        }
        if (l1 != NULL) l1 = l1->next; // 如果 l1 不为空,移动到下一个节点
        if (l2 != NULL) l2 = l2->next; // 如果 l2 不为空,移动到下一个节点
    }
    if (carry > 0) { // 如果最高位有进位,创建一个节点存储进位,并将其添加到新链表的末尾
        struct ListNode* node = (struct ListNode*)malloc(sizeof(struct ListNode));
        node->val = carry;
        node->next = NULL;
        tail->next = node;
        tail = node;
    }
    return head; // 返回新链表的头节点
}

2、16ms 版本,比较容易想到,时间消耗比较长!

struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) {
    struct ListNode* rear, *sum_head = NULL;
    int sum_left = 0, left = 0;
    /*Implementing the addition process*/
    while(l1 != NULL && l2 != NULL){
        /*Create a new node by tail-inserting way*/
        struct ListNode* p;
        p = (struct ListNode*) malloc (sizeof(struct ListNode));
        p -> next = NULL;
        if(!sum_head)   sum_head = p;
        else rear -> next = p;
        rear = p;
        /*the adding process*/
        sum_left = (l1->val + l2->val + left) % 10;
        left = (l1->val + l2->val + left) / 10;
        p -> val = sum_left;
        /*Move the nodes of l1 and l2 back one bit*/
        l1 = l1 -> next; 
        l2 = l2 -> next;
    }
    if(l1){ //if the length of l1 is longer
        rear -> next = l1;
        while(l1){
            sum_left = (l1->val + left) % 10;
            left = (l1->val + left) / 10;
            l1->val = sum_left;
            if(left == 0) break;
            else{
                rear = l1;
                l1 = l1->next;
            }
        }
        if(l1 == NULL && left != 0){
            struct ListNode* p;
            p = (struct ListNode*) malloc (sizeof(struct ListNode));
            p->val = left;
            p->next = NULL;
            rear->next = p;
        }
    }
    else{   //if the length of l2 is longer
        rear -> next = l2;
        while(l2){
            sum_left = (l2->val + left) % 10;
            left = (l2->val + left) / 10;
            l2->val = sum_left;
            if(left == 0) break;
            else{
                rear = l2;
                l2 = l2->next;
            }
        }
        if(l2 == NULL && left != 0){
            struct ListNode* p;
            p = (struct ListNode*) malloc (sizeof(struct ListNode));
            p->val = left;
            p->next = NULL;
            rear->next = p;
        }
    }
    return sum_head;
}

(五)做题收获

        本题中,我们学会了巧妙使用三元条件表达式,这一步大大减少了程序所消耗的时间。熟悉了大整数加法的按位运算以及链表的创建与连接。虽然难度不大,但涉及面也十分广泛。

  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值