欢迎访问宙启技术站
智能推送

LeetCode实现两数求和

发布时间:2023-05-15 12:50:57

两数求和是一道经典的算法题,也是很多面试中出现的常见题目。在这篇文章中,我们将介绍LeetCode上两数求和的题目,并给出一些可行的解决方案。

1.题目描述

题目描述如下所示:

给定两个非空的链表,表示两个非负整数。其中每个节点只存储一位数字,将这两个数字相加并以链表形式返回。

假设这两个数字的最高位数字在链表头部。

例如:

输入:(7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)

输出:7 -> 8 -> 0 -> 7

解释:3427 + 465 = 3892,因此结果链表表示的数字为 7893,即 7 -> 8 -> 9 -> 3。

2.解决方案

这道题可以使用多种不同的解决方案。常见的解决方案包括使用递归、迭代和栈。

2.1.递归

使用递归的解决方案可能会更简洁优美。具体来说,我们可以定义一个递归函数,它负责计算两个链表当前节点的和,并将进位值传递到下一次递归调用中。在递归的过程中,我们可以创建一个新节点,将其值设为当前节点的和,然后返回这个新节点。

递归的关键是确定递归停止的条件。在这个问题中,我们需要考虑两个链表都为空的情况,并且当一个链表为空时,我们只需要将另一个链表的节点之和放入结果中。

下面是递归解决方案的示例代码:

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

struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) {
    return addTwoNumbersImpl(l1, l2, 0);
}

struct ListNode* addTwoNumbersImpl(struct ListNode* l1, struct ListNode* l2, int carry) {
    if (l1 == NULL && l2 == NULL && carry == 0) {
        return NULL;
    }

    int value = carry;
    if (l1 != NULL) {
        value += l1->val;
        l1 = l1->next;
    }
    if (l2 != NULL) {
        value += l2->val;
        l2 = l2->next;
    }

    struct ListNode* result = (struct ListNode*)malloc(sizeof(struct ListNode));
    result->val = value % 10;
    result->next = addTwoNumbersImpl(l1, l2, value / 10);

    return result;
}

在这个代码中,我们定义了一个addTwoNumbers函数,它将l1和l2传递给addTwoNumbersImpl函数,并将初始进位值设为0。addTwoNumbersImpl函数根据当前节点的值和前一步的进位值,计算当前节点的和,并递归地调用下一个节点。在计算当前节点值时,我们还必须检查链表是否为空,以防止出现空指针错误。最后,我们需要使用malloc函数为结果分配新节点。

2.2.迭代

迭代的解决方案通常比递归更快,因为递归需要产生更多的函数调用。迭代解决方案依次对每一对节点进行相加,并将进位值存储在一个变量中,供下一次迭代使用。遍历完所有节点后,我们要检查进位值是否为0,如果不为0,则需要创建一个新节点。

下面是迭代解决方案的示例代码:

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

struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) {
    struct ListNode* result = (struct ListNode*)malloc(sizeof(struct ListNode));
    result->val = 0;
    result->next = NULL;

    struct ListNode* tail = result;
    int carry = 0;
    while (l1 != NULL || l2 != NULL) {
        int value = carry;
        if (l1 != NULL) {
            value += l1->val;
            l1 = l1->next;
        }
        if (l2 != NULL) {
            value += l2->val;
            l2 = l2->next;
        }
        carry = value / 10;

        struct ListNode* node = (struct ListNode*)malloc(sizeof(struct ListNode));
        node->val = value % 10;
        node->next = NULL;
        tail->next = node;
        tail = node;
    }

    if (carry != 0) {
        struct ListNode* node = (struct ListNode*)malloc(sizeof(struct ListNode));
        node->val = carry;
        node->next = NULL;
        tail->next = node;
        tail = node;
    }

    return result->next;
}

在这个代码中,我们首先创建了一个结果节点,该节点的值为0,并且没有任何后继节点。然后我们创建了一个指向结果节点的tail指针,用于追踪最后一个节点。在迭代期间,我们对每对节点执行相加操作,并在尾部插入一个新节点。我们使用carry变量存储进位值,并在下一次循环中使用。如果迭代完成后carry不为零,则需要创建一个新节点并插入结果链表的末尾。

2.3.栈

使用栈也是一种可行的解决方案。首先,我们需要将一对一对的节点以相反的顺序存储在两个栈中(因为输出的数字的高位在前面)。然后我们可以依次将栈中的节点弹出,并执行相加操作和进位操作,并将结果存储在一个新节点上。

下面是栈解决方案的示例代码:

`

/**

* Definition for singly-linked list.

* struct ListNode {

* int val;

* struct ListNode *next;

* };

*/

struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) {

struct ListNode* result = NULL;

struct ListNode* tail = NULL;

struct Stack* stack1 = createStack();

struct Stack* stack2 = createStack();

while (l1 != NULL) {

push(stack1, l1->val);

l1 = l1->next;

}

while (l2 != NULL) {

push(stack2, l2->val);

l2 = l2->next;

}

int carry = 0;

while (!isEmpty(stack1) || !isEmpty(stack2)) {

int value = carry;

if (!isEmpty(stack1)) {

value += pop(stack1);

}

if (!isEmpty(stack2)) {

value += pop(stack2);

}

carry = value / 10;

struct ListNode* node = (struct ListNode*)malloc(sizeof(struct ListNode));

node->val = value % 10;

node->next = NULL;

if (tail == NULL) {

result = node;

} else {

tail->next = node;

}

tail = node;

}

if (carry != 0) {

struct ListNode* node = (struct ListNode*)malloc(sizeof(struct ListNode));

node->val = carry;

node->next = result;

result = node;

}

return result;

}

struct Stack {

int *items;

int top;

int size;

};

struct Stack* createStack() {

struct Stack* stack = (struct Stack*)malloc(sizeof(struct Stack));

stack->size = 1024;

stack->items = (int*)malloc(stack->size * sizeof(int));

stack->top = -1;

return stack;

}

int isEmpty(struct Stack* stack) {

return stack->top == -1;

}

int isFull(struct Stack* stack) {

return stack->top == stack->size - 1;

}

void push(struct Stack* stack, int item) {

if (isFull(stack)) {

return;

}

stack->items[++stack->top] = item;

}

int pop(struct Stack* stack) {

if (isEmpty(stack)) {

return 0;