【问题标题】:Error in Adding Two Numbers (digits in linked list)添加两个数字时出错(链表中的数字)
【发布时间】:2015-05-04 05:18:16
【问题描述】:

这是关于https://oj.leetcode.com/problems/add-two-numbers/的问题

给定两个链表,表示两个非负数。 数字以相反的顺序存储,它们的每个节点都包含 一个数字。将两个数字相加并作为链表返回。

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

输出:7 -> 0 -> 8

我遵循的逻辑是我假设 list1 比 list2 长,否则交换它们。然后,我通过在 list2 的末尾添加包含零的节点来使 list2 的长度等于 list1。 (此时代码会打印两个列表以检查是否存在错误)。在此之后,我从头开始遍历列表,添加单个数字,用数字总和模 10 覆盖链表 1 中的值。还记录了进位值。这样做直到列表结束。如果最后进位值不为零,则创建一个包含进位值的新节点,并将其插入到链表1的末尾。返回链表1的头。

代码在所有情况下都能正常工作,除了必须在最后添加一个带有进位值的新节点的情况。我在返回值之前打印链表 1,此时它是正确的。但是,返回头部并在主函数中打印它会给出错误的答案,节点中应该包含进位数字的垃圾值。这几乎就像带有进位数字的节点被2-3个带有垃圾值的节点所取代。有人可以解释一下吗?

我观察到的另一个问题是在打印最终答案时,如果我使用cout << ans->val << " " << endl,代码会正确终止(返回 0)但会打印不正确的输出。如果我删除 endl ,即使用 cout << ans->val << " " ,则代码会通过引发运行时错误(段错误)终止。我想不出一个合适的理由。

感谢您的时间和帮助。

#include <iostream>

using namespace std;

struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};

class Solution {
public:
    ListNode *addTwoNumbers(ListNode *l1, ListNode *l2)
    {
      ListNode* l1_mover = l1;
      ListNode* l2_mover = l2;
      while ((l1_mover->next != NULL) && (l2_mover->next != NULL))
      {
        l1_mover = l1_mover->next;
        l2_mover = l2_mover->next;
      }
      if ((l1_mover->next == NULL) && (l2_mover->next != NULL))
      {
        // Call the function after swapping the lists if the first one is smaller
        cout << "calling function with swapped lists " << endl;
        return addTwoNumbers(l2, l1);
      }
      while (l1_mover->next != NULL)
      {
        ListNode emp(0);
        l2_mover->next = &emp;
        l1_mover = l1_mover->next;
      }
      // Till now, I have equated the lengths of both the lists, by padding the shorter one with zeros.

      cout << "printing list 1 inside. " << endl;
      l1_mover = l1;
      while (l1_mover != NULL)
      {
        cout << l1_mover->val << " ";
        l1_mover = l1_mover->next;
      }
      cout << endl;

      cout << "printing list 2 inside. " << endl;
      l2_mover = l2;
      while (l2_mover != NULL)
      {
        cout << l2_mover->val << " ";
        l2_mover = l2_mover->next;
      }
      cout << endl;
      // The above two print statements show that the lists are still correct
      l1_mover = l1;
      l2_mover = l2;
      int carry = 0;
      while (l1_mover != NULL)
      {
        int digit_sum = l1_mover->val + l2_mover->val + carry;
        carry = digit_sum / 10;
        l1_mover->val = digit_sum % 10;
        //cout << "sum is " << digit_sum << " and l2 val is " << l2_mover->val << endl;
        if (l1_mover->next == NULL)
          break;
        // the above break is so that l1 is not NULL at end of loop.
        l1_mover = l1_mover->next;
        l2_mover = l2_mover->next;
      }
      if (carry != 0)
      {
        cout << "carry not zero " << carry  << endl;
        ListNode last_one(carry);
        l1_mover->next = &(last_one);
      }
      cout << endl << "printing ans inside. " << endl;
      l1_mover = l1;
      while (l1_mover != NULL)
      {
        cout << l1_mover->val << " ";
        l1_mover = l1_mover->next;
      }
      cout << endl << endl;
      // The above lines print the linked list containing the sum. It is observed to be correct.
      return l1;
    }
};

int main()
{
  ListNode a1(8);
  ListNode b1(7);
  ListNode b2(9);
  b1.next = &b2;
  Solution object;
  ListNode* ans = object.addTwoNumbers(&a1, &b1);
  cout << "printing ans " << endl;
  while (ans != NULL)
  {
    cout << ans->val << " " << endl;
    // cout << ans->val << " "; // if this line is used, instead of the above one,
    // the program terminates with an error message. It doesn't give an error if the other line
    // is used.
    ans = ans->next;
  }
}

【问题讨论】:

  • 复制粘贴编译你的代码和代码段错误,你也明白了吗?
  • 在终端打印很多东西后是否出现了段错误?包括句子“printing ans”。我在问题的第二部分提到了这一点。我只在第二种情况下遇到段错误。但是,这可能是我的机器特有的。因此,为了回答您的查询,在打印很多内容(包括“打印 ans”)后会出现段错误。在此之前,它不是。
  • 您正在存储指向在您访问它们时生命周期已结束的对象的指针(&amp;emp&amp;last_one)。您需要动态分配。
  • 为什么要先补零?这似乎是一个不必要的步骤 - 遍历列表求和;当您点击NULL 时停止更新该指针,并添加0
  • @molbdnilo:谢谢。我知道问题与范围和内存分配有关。只是我认为以我的方式调用构造函数与动态分配相同。回想起来,这似乎是一个愚蠢的想法。修复了代码。

标签: c++ list


【解决方案1】:
ListNode last_one(carry);
l1_mover->next = &(last_one);

然后你 return l1 ; 而最后一个节点是本地的

编辑:我改变了它并且现在可以完美地工作,但我只指出了问题,如果你也想要解决方案,请告诉我,我会的

void print( ListNode * l )
{
    if( l )
    {
        print( l->next ) ;
        cout << l->val ;
    }
}

【讨论】:

    【解决方案2】:

    为什么不直接读取每个链表,提取它们的预期值,执行操作(加法),然后将其重新编码为链表?

    链表已经反向排序,这使得添加额外位置的逻辑更容易。

    即如果您要将链表概念化为数组...

    (linked_list[0] * 1) + (linked_list[1] * 10) + (linked_list[2] * 100)
    

    等等等等。

    然后,将它们加在一起,因为它们都是整数,我们可以使用模数并重新编码:

    sum = linked_list_num_1 + linked_list_num_2;
    
    int n = 0;
    
    while (sum != 0)
    { 
        result_linked_list[n] = sum % 10;
        sum = sum / 10;
        ++n;
    }
    

    我现在正在自己的班级中做链表容器,看来您可以为列表编写一个轻量级容器,以便您至少可以轻松地添加和提取节点。

    【讨论】:

    • 输入数字的大小没有限制,因此它们可能不适合任何内置整数类型。
    • 我知道。我只是将链表概念化为一个很好的衡量标准。您可以轻松地将任何访问功能替换为 get(int index) 之类的链接列表,并完成边界检查等。
    猜你喜欢
    • 2015-01-08
    • 2020-04-07
    • 1970-01-01
    • 1970-01-01
    • 2021-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多