【问题标题】:merging k sorted lists does not work with negative values C#合并 k 个排序列表不适用于负值 C#
【发布时间】:2021-07-01 17:29:46
【问题描述】:

问题的问题是: 给定一个由 k 个链表组成的数组,每个链表按升序排序。 将所有链表合并为一个排序的链表并返回。 一个成功的输入和输出示例是:

Input: lists = [[1,4,5],[1,3,4],[2,6]]
Output: [1,1,2,3,4,4,5,6]
Explanation: The linked-lists are:
[
  1->4->5,
  1->3->4,
  2->6
]
merging them into one sorted list:
1->1->2->3->4->4->5->6

我的代码的问题是它不适用于负值,但它适用于正值。 例如输入-> [[2],[1],[-1]] 输出->[1,2]

  public class Solution {
   public ListNode MergeKLists(ListNode[] lists) {
       if (lists.Length == 0) return null;
       var newlist = new ListNode();
       var result = newlist;
       for(int i=0; i<lists.Length; i++)
       {
           if(lists[i] !=null)
           newlist = MergeTwoLists(lists[i], newlist);
       }
       return result.next;
    }

    

    private ListNode MergeTwoLists(ListNode l1, ListNode l2) {
        if (l1 == null)
            return l2;
        if (l2 == null)
            return l1;
        if (l1.val <= l2.val)
        {
            l1.next = MergeTwoLists(l1.next, l2);
            return l1;
        }
        else
        {
            l2.next = MergeTwoLists(l1, l2.next);
            return l2;
        }
    }
}

【问题讨论】:

  • 阅读this article 了解调试代码的技巧。
  • 您的示例是否适用于[[3], [2], [1]]?我怀疑它没有,所以专门查看负值会导致你走错路,因为可能存在更严重的错误。
  • 提示:你的“基础”列表(即newlist)从一个节点开始。该节点中的val 是什么?将这些知识与一个完全不同的事实结合起来:当您在代码中对newlist 进行操作时,您在方法中返回 result.next,而不是newlist.next。关于这两个事实,请注意您从 非空列表开始您的算法。您似乎试图用第二个错误来抵消该错误,即返回 result.next 而不是 newlist。这些错误结合起来产生您看到的结果。
  • @Code-Apprentice:您的示例可以正常工作。代码确实在负值方面被破坏了,这是代码中两个完全不同的错误的结果,它们部分地相互平衡以隐藏任何合并到结果中的负数。

标签: c# list merge


【解决方案1】:

基本上,您的代码的问题在于您使用非空列表初始化算法。 IE。您将 newlist 设置为单个 ListNode 对象。您还没有提供完整的代码示例,但大概这是一个至少有两个成员的类,valnext。在 C# 中,这两个成员最初都会有它们的默认值,这意味着您从列表 [0] 开始,甚至在您开始合并任何内容之前。

还请注意,当您在合并循环中修改newlist 变量时,您返回 的是result.next 变量。这似乎是试图跳过您首先放入newlist 列表中的错误包含0 值。但在您的负值示例中,它会导致您跳过 0 值,合并正确放置在它之前的 -1 值。

在您的示例[[2],[1],[-1]] 中,这意味着当合并循环完成时,您有newlist 引用列表[-1, 0, 1, 2]。但是result 指向该列表的第二个元素(原来的0-valued 节点),给你[0, 1, 2]。那么你返回的是that的下一个节点,它产生[1,2]

事实是,您展示的 MergeTwoLists() 方法已经处理空列表,即空值列表。目前尚不清楚是什么促使您使用非空列表初始化算法,也不清楚是什么促使您保留第二个变量来引用同一个节点。如果你没有做后者,你的问题可能会更容易被你注意到,当然,整个 bug 都是由前者引起的。

您应该从已有的代码中删除这两个方面。将newlist 初始化为null,而不是为其创建新节点,并完全摆脱result 变量:

public ListNode MergeKLists(ListNode[] lists) {
    var newlist = null;
    for (int i = 0; i < lists.Length; i++)
    {
        if (lists[i] != null) {
            newlist = MergeTwoLists(lists[i], newlist);
        }
    }
    return newlist;
}

注意:您也不需要检查lists.Length == 0。如果lists.Length0,则循环将被跳过,并且在这种情况下,固定版本只是将null 作为空列表返回,没有它也可以正常工作。

更笼统地说:大多数时候,错误是通过更改代码来修复的,甚至可以删除它。如果您养成了通过添加代码来修复错误的习惯,那么您通常会在已有错误的基础上添加一个新错误。

我承认,这条规则并不是一成不变的、100% 可靠的规则。但多年来,它对我很有帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-03-20
    • 2018-05-16
    • 2013-10-28
    • 1970-01-01
    • 2019-09-12
    • 1970-01-01
    • 1970-01-01
    • 2011-02-11
    相关资源
    最近更新 更多