面试:在两个链接列表中汇总数字

时间:2011-10-26 13:22:11

标签: c++ list recursion linked-list

在昨天的一次采访中,我被问到如何总结两个包含数字的单链表的值。他们还说这些名单可能不等。

我问这个列表是否是向后存储的,因为这是我在大学学习它的方式,但他们说不,它是向前存储的。他们还说我不能简单地反转列表,然后添加,然后反转它以使其再次前进,因为该选项需要太多处理。我在网上找到了这种解决方案。

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

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

对于那些对总和应该如何工作感到困惑的人,它就是以这种方式呈现的。

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

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

4 个答案:

答案 0 :(得分:4)

您计算两个列表的长度。您在较短的列表的开头填充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链接列表。你只给出了第一级Sum和Run Total的“头部”。
  • 在“版本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)

我会在这样的问题上解决这个问题

我们假设2个列表是:
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;

注意::我们可以轻松处理下一个传递中的进位,或者您可以在我们的和函数本身处理

所以这毕竟我们的ans将是1->2->7->11->11->5 然后递归地执行%10并带进并将其添加到先前的值。

所以最终的答案是1->2->8->2->1->5

答案 2 :(得分:0)

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

至于递归,只需在函数顶部检查并返回(node-&gt; value + myfunct(node-&gt; prev));如果你做一次数学运算会更有效率。

答案 3 :(得分:0)

列表“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]

作为替代方案,您可以使用堆栈:

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