【力扣一题】两数相加(C)

这段代码定义了一个函数addTwoNumbers,用于将两个单链表表示的数字相加。它使用了两个指针res和pre来构建新的结果链表,res始终指向链表头,pre则跟踪最后一个已添加的节点。在循环中,根据当前链表节点值和进位计算新节点值,并更新链表结构。最后返回结果链表的下一个节点,即不包含初始0值的头节点。

 

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


struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){
    struct ListNode* res = (struct ListNode*)malloc(sizeof(struct ListNode));
    res->val = 0;
    res->next = NULL;
    struct ListNode* pre = res;
    int carry = 0;//首先定义一个指向结果链表头结点的指针res,以及一个指向上一个节点的指针pre。将进位值carry初始化为0。

    while(l1 || l2 || carry) //接下来进行循环,条件为l1或l2不为NULL,或者存在进位carry
    {
        struct ListNode* temp = (struct ListNode*)malloc(sizeof(struct ListNode));
        int n1 = l1 ? l1->val :0 ;
        int n2 = l2 ? l2->val :0 ;
        int sum = n1 + n2 + carry;
        //定义一个新节点temp,并将l1和l2节点的值相加,同时加上进位值carry,得出本次节点值的和sum。
        
        temp->val = sum % 10;
        temp->next =NULL;
        pre->next = temp; //将temp连接到pre节点后面,同时更新pre节点为temp。

        pre = pre->next;
        carry = sum / 10;
        l1 = l1 ? l1->next : NULL ;
        l2 = l2 ? l2->next : NULL ;
    }
    return res->next;
}

注释如上,么么!

注意了:

pre和res是两个指针变量,分别用于构建新的结果链表。具体说明如下:

res指针指向结果链表的头节点,其初始值为一个新创建的节点(通过malloc函数动态分配)。之后,我们根据每次相加的结果将新的节点接在pre节点后面,来实现结果链表的构建。可以将res看作是整个结果链表的“起点”。

pre指针用于存储上一个节点的位置,在循环中,我们在每次处理完当前节点之后,将该节点添加到结果链表的尾部(即接在pre节点后面)。因此,pre指针实际上指向的是结果链表中最后一个节点的位置(随着循环的进行而不断更新)。可以将pre看作是结果链表的“终点”。

需要注意的是,在循环中,pre指针的起始值与res指针是相等的,即它们最初都指向结果链表的头节点。

我的理解为,res是一个老大,老大是不变的,然后pre再通过struct ListNode* pre = res;后res作为老大的小弟给老大忙前忙后,帮助老大拼接身体,最后返回老大的值。

力扣第2题要求将两个非空链表表示的逆序整数相加,并以相同形式返回结果链表。这两个整数的每一位都存储在链表节点中,且数字以逆序方式存储。解法需要考虑进位处理以及链表操作。 以下是一个完整的 C 语言解法示例: ```c #include <stdio.h> #include <stdlib.h> // 定义链表节点结构 struct ListNode { int val; struct ListNode *next; }; // 实现两数相加的函数 struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) { struct ListNode *dummyHead = (struct ListNode*)malloc(sizeof(struct ListNode)); // 虚拟头节点 struct ListNode *current = dummyHead; // 当前节点指针 int carry = 0; // 进位值 while (l1 != NULL || l2 != NULL || carry != 0) { int val1 = (l1 != NULL) ? l1->val : 0; int val2 = (l2 != NULL) ? l2->val : 0; int sum = val1 + val2 + carry; carry = sum / 10; struct ListNode *newNode = (struct ListNode*)malloc(sizeof(struct ListNode)); newNode->val = sum % 10; newNode->next = NULL; current->next = newNode; current = current->next; if (l1 != NULL) l1 = l1->next; if (l2 != NULL) l2 = l2->next; } return dummyHead->next; // 返回结果链表的头节点 } ``` ### 解法说明: 1. **虚拟头节点**:使用 `dummyHead` 来简化链表的构造过程,避免对头节点的特殊处理。 2. **进位处理**:通过 `carry` 变量记录每次相加的进位值。 3. **遍历链表**:使用 `while` 循环遍历两个链表,直到两个链表都到达末尾且没有进位为止。 4. **构造结果链表**:每次循环创建一个新节点,存储当前位的和(模10的结果),并将其链接到结果链表中。 5. **边界条件处理**:如果链表长度不一致,或最后仍有进位,则继续处理。 该算法的时间复杂度为 O(max(m, n)),其中 m 和 n 分别是两个链表的长度。空间复杂度也为 O(max(m, n)),用于存储结果链表[^4]。 --- ### 示例输入输出 假设输入链表 `l1` 为 `2 -> 4 -> 3`,表示数字 `342`,输入链表 `l2` 为 `5 -> 6 -> 4`,表示数字 `465`,则输出链表为 `7 -> 0 -> 8`,表示数字 `807`。 --- ### 代码测试建议 1. 创建两个链表 `l1` 和 `l2`,分别表示两个数字。 2. 调用 `addTwoNumbers` 函数,获取结果链表。 3. 遍历结果链表,打印每个节点的值,验证是否正确。 --- ### 代码优化 - **内存管理**:确保每次 `malloc` 后检查是否成功分配内存,避免程序崩溃。 - **链表释放**:在测试完成后,应手动释放动态分配的链表节点,防止内存泄漏。 --- ### 测试代码 以下是一个简单的测试代码片段: ```c // 创建链表节点的辅助函数 struct ListNode* createNode(int val) { struct ListNode* node = (struct ListNode*)malloc(sizeof(struct ListNode)); node->val = val; node->next = NULL; return node; } // 打印链表的辅助函数 void printList(struct ListNode* head) { while (head != NULL) { printf("%d ", head->val); head = head->next; } printf("\n"); } int main() { // 创建链表 l1: 2 -> 4 -> 3 struct ListNode* l1 = createNode(2); l1->next = createNode(4); l1->next->next = createNode(3); // 创建链表 l2: 5 -> 6 -> 4 struct ListNode* l2 = createNode(5); l2->next = createNode(6); l2->next->next = createNode(4); // 计算两数之和 struct ListNode* result = addTwoNumbers(l1, l2); // 打印结果 printList(result); return 0; } ``` --- ### 相关问题 1. 如何在 C 语言中实现链表的反转? 2. 力扣第 2 题的进位处理逻辑是什么? 3. 如何在 C 语言中高效管理动态分配的链表内存? 4. 力扣题目中链表操作的常见技巧有哪些? 5. C 语言中如何避免链表操作中的空指针异常?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值