繁体   English   中英

访谈:将两个链表中的数字相加

[英]Interview: Summing numbers in two linked lists

在昨天的一次采访中,有人问我如何对两个包含数字的单链接列表的值求和。 他们还说,名单的长度可能不相等。

我问列表是否向后存储,因为这是我在uni中学到的,但是他们说不,它被向前存储。 他们还说,我不能简单地颠倒列表,然后添加,然后颠倒它以使其再次前进,因为该选项需要太多的处理。 我可以在网上找到所有这种解决方案。

即使他们暗示我应该使用递归函数来执行此操作,我也无法给出答案。

任何人都可以帮助我解决该问题的方法。 这是用于C ++的工作,我希望,如果能给我回电话,并且能够解释我研究了该解决方案,他们可能会认为这是一个好兆头。 谢谢。

对于那些对求和应该如何工作感到困惑的人,可以通过这种方式进行介绍。

清单1:1-> 2-> 9清单2:1-> 3

因此,由于数字是向前存储的,因此我需要先添加9和3(两个列表的末尾)。 然后进行1进位并执行1 + 2 + 1等。

您计算两个列表的长度。 您在较短的列表的开头填充数字0,以使它们的长度相等。 现在,您将两个数字都加一个额外的0(第一个数字的进位将使用它。因此,可能9 + 1 = 10)。 您创建第三个链接列表,其长度等于前两个。

现在,您进行如下课程:

class Digit
{
    public:
    Digit *Next;
    int Dt;
}

和这样的功能:

int Sum(const Digit* left, const Digit* right, Digit* runningTotal)
{
    int carry = 0;

    if (left->Next != NULL)
    {
        carry = Sum(left->Next, right->Next, runningTotal->Next);
    }

    carry += left->Dt + right->Dt;

    runningTotal->Dt = carry % 10;

    carry /= 10;

    return carry;
}
  • 这是“版本0”。
  • 在“版本1”中,删除最后一个进位的多余填充,仅在需要时才添加。
  • 在“版本2”中,从链接列表的开头删除不必要的“ 0”数字。
  • 在“版本3”中,直接在Sum中创建runningTotal链接列表。 您将第一个级别的总和作为“总计”的“头”。
  • 在“版本4”中,而不是填充较短的LL,而是在要从最长的LL(这是最困难的段落)中跳过的位数上传递参数。

还有另一种可能性,复杂得多,但这不需要预先计算列表的长度。 它使用两个递归函数:

第一个递归函数仅在同时出现时向左和向右遍历。 如果两者都同时完成,则可以像上一个示例一样简单地回滚。

如果其中一个先于另一个完成,则可以使用另一个递归函数(* extraDigits的初始值为1):

void SaveRemainingDigits(const Digit *remaining, int *extraDigits, int **buffer)
{
    int currentDigit = *extraDigits - 1;

    *extraDigits = *extraDigits + 1;

    if (remaining->Next)
    {
        SaveRemainingDigits(remaining->Next, extraDigits, buffer);    
    }
    else
    {
        *buffer = (int*)malloc(sizeof(int) * extraDigits);
    }

    (*buffer)[currentDigit] = remaining->Dt;
}

当此函数最终返回时,我们便有了一个便签本,可以从中提取数字和便签本的长度

现在,我们第一个递归函数的最内层必须将其最短链接列表的当前数字与暂存器的最后一位数字相加,然后将最长链接列表的当前数字放在暂存器中,以代替刚刚使用的数字。 现在,您展开递归函数,然后将暂存器用作循环数组。 完成展开后,可以将元素添加到runningTotal链接列表,直接从暂存器中获取它们。

正如我所说的,这有点复杂,但是我可以在1-2个小时内将其记录为一个程序。

一个例子(不带进位)

1 2 3 4
6 5

您递归前两个元素。 所以你有了

1-6 (in the first level)
2-5 (in the second level)

现在,您看到第二个列表已完成,并使用了第二个功能。

3 (extraDigit enters as 0, is modified to 1. currentDigit = 0)
4 (extraDigit enters as 1, is modified to 2. currentDigit = 1. 
   malloc of 2 elements,
   buffer[currentDigit] = 4 => buffer[1] = 4)

unroll and we return to the previous row

3 (currentDigit = 0
   buffer[currentDigit] = 3 => buffer[0] = 3)

现在我们返回上一个功能

2-5 (in the second level, 
     with a lengthBuffer == 2, 
     we set index = length(buffer) - 1
     currentDigitTotal = 5 + buffer[index] => currentDigitTotal = 5 + 4
     buffer[index] = 2 => buffer[1] = 2;
     index = (index - 1 + lengthBuffer) % lengthBuffer => index = 0

1-6 (in the first level, 
     with a lengthBuffer == 2, 
     index = 0,
     currentDigitTotal = 6 + buffer[index] => currentDigitTotal = 6 + 3
     buffer[index] = 1 => buffer[0] = 1;
     index = (index - 1 + lengthBuffer) % lengthBuffer => index = 1

now we exited the recursive function. 
In an external function we see that we have a buffer. 
We add its elements to the head of the total.

Our Linked list now is 9-9 and our buffer is 1,2 with index 1

for (int i = 0; i < lengthBuffer; i++)
{
    runningTotal.AddHead(buffer(index));
    index = (index - 1 + lengthBuffer) % lengthBuffer
}

我将以这种方式解决这个问题

假设这两个列表是:
1-> 2-> 7-> 6-> 4-> 3和
5-> 7-> 2

总和是1->2->7 + Sum(6->4->3, 5->7->2)

现在我们创建一个函数,该函数接受2个大小相同的列表并返回它们的总和

就像

list1->val + list2->val + Sum(list1->next, list2->next)

基本情况下if(list1->next == NULL) return list1->val+list2->val;

注意::我们可以轻松处理下一遍的进位,也可以在我们的sum函数本身中处理

因此,所有这些之后,ans将是1->2->7->11->11->5然后递归执行%10并带进位并将其添加到先前的值。

所以最终ans将是1->2->8->2->1->5

我将创建一个像* head或* tail的节点来存储我从其开始的节点的地址,然后遍历列表以确保im不会回到我的起点。 这不需要必须计算每个的长度,这听起来效率很低。

至于递归性,只需在函数顶部进行此检查并返回(node-> value + myfunct(node-> prev)); 考虑到您只需进行一次数学运算,效率会更高。

列表“ 1、2、9”和“ 1、3”分别代表数字“ 129”和“ 13”,在这种情况下,总和为“ 142”。

使用递归

  • 计算每个列表的长度。
  • 如果长度不同,则在开始处用零填充最短的长度。
  • 递归遍历列表,返回:a)进位号(如果有),否则返回零,以及b)列表的尾部。

用伪代码:

def sum_lists_rec(a, b, start_a, start_b, length_a, length_b):
    """Returns a pair of two elements: carry and the tail of the list."""

    if the end of the lists:
        return (0, empty_list)

    result = sum_lists_rec(a+1, b+1, start_a+1, start_b+1, length_a, length_b)

    carry = (a[0] + b[0] + result[0]) / 10
    digit = (a[0] + b[0] + result[0]) % 10

    return (carry, [digit] ++ result[1])

def sum_lists1(a, b):
    length_a = length(a)
    length_b = length(b)

    if length_a < length_b:
        a = [0, 0, ..., (length_b - length_a)] ++ a
    else if length_b < length_a:
        b = [0, 0, ..., (length_a - length_b)] ++ b

    result = sum_lists_rec(a, b, length_a, length_b, 0, 0)

    if result[0] != 0:
        return [result[0]] ++ result[1]
    else:
        return result[1]

或者,您可以使用堆栈:

  • 计算每个列表的长度。
  • 如果长度不同,则在开始处用零填充最短的长度。
  • 将两个列表的每个数字压入堆栈。
  • 弹出堆栈,直到为空,创建新列表。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM