【问题标题】:merge K sorted lists, not working for edge cases, like null, and only 2 lists C++合并 K 个排序列表,不适用于边缘情况,例如 null,并且只有 2 个列表 C++
【发布时间】:2020-07-27 09:03:58
【问题描述】:

所以代码适用于列表数量大于 3 且没有空列表的情况,但在有两个或更少列表或空列表时显示错误 我正在比较每个列表的第一个元素并将 S 指向具有最小值的那个,然后我将具有最小值的节点指向它的下一个元素,直到它为空,当所有列表达到/变为空时,我打破循环并返回 head->next

for example
input = [[1,4,5],[1,3,4],[2,6]]
my output = [1,1,2,3,4,4,5,6]
expected = [1,1,2,3,4,4,5,6] this one is correct
but when a null list is there
example: input = [[1,4,5],[],[1,3,4],[2,6]]
it returns an error something like: AddressSanitizer: heap-buffer-overflow on address 0x...... error continues

=================================================================
==32==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x603000000060 at pc 0x000000381d29 bp 0x7ffd73c87f70 sp 0x7ffd73c87f68
READ of size 8 at 0x603000000060 thread T0
    #3 0x7f28a234a82f  (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
0x603000000060 is located 0 bytes to the right of 32-byte region [0x603000000040,0x603000000060)
allocated by thread T0 here:
    #6 0x7f28a234a82f  (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
Shadow bytes around the buggy address:
  0x0c067fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c067fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c067fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c067fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c067fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c067fff8000: fa fa 00 00 00 07 fa fa 00 00 00 00[fa]fa fa fa
  0x0c067fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==32==ABORTING

代码:

    /**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        ListNode* S = new ListNode();
        ListNode* head = S;
        int N = lists.size();
        int min = 0, count = 1;
        
        while ( count )
        {
            int k = 0;
            while( lists[k] == NULL && k < N )
                ++k;
            if( k == N  )
                break;
            min = k;
            count = 0;
            for(int j = 0; j < N; j++ )
            {
                if (lists[j] != NULL )
                {
                    if( lists[j]->val < lists[min]->val)
                        min = j;
                    
                    ++count;
                }
            }
            if( count == 0 )
                break;
            S->next = lists[min];
            S = S->next;
            if( lists[min] != NULL )
                lists[min] = lists[min]->next;
        }
        return head->next;
    }
};

【问题讨论】:

  • 提供输入、当前输出和预期输出。
  • 如果所有列表都是空的怎么办?循环while (lists[k] == NULL) ++k; 会融化你的处理器。
  • 如果所有列表都是空的,K 应该等于 N(列表数量)并且循环应该中断,head->next 应该返回,它应该是 NULL 你是什么意思它会融化处理器,它不应该只是循环遍历向量,如果列表为空,只需增加 K 吗?
  • N 根本没有出现在 while 循环中。会怎么破?当k 命中lists.size() 时,您将获得 UB。
  • “融化处理器”只是个玩笑。 :) 你会得到未定义的行为。

标签: c++


【解决方案1】:

如果您将 lists 修剪为只有非空列表,则可以删除大部分对 nullptr 的检查。你也在泄露head

bool compareNode(ListNode * lhs, ListNode * rhs) {
    return lhs->val < rhs->val;
}

ListNode* mergeKLists(std::vector<ListNode*>& lists) {
    lists.erase(std::remove(lists.begin(), lists.end(), nullptr), lists.end());

    ListNode* head = nullptr;
    ListNode* curr = nullptr;
    
    while ( !lists.empty() )
    {
        auto it = std::min_element(lists.begin(), lists.end(), compareNode);
        if(head) {
            curr->next = *it;
        } else {
            curr = head = *it;
        }

        if (ListNode* next = (*it)->next) {
            *it = next;
        } else {
            lists.erase(it);
        }
    }

    return head;
}

【讨论】:

    【解决方案2】:

    所以问题是这种情况:

    while( lists[k] == NULL && k < N )
                ++k;
    

    当K = N - 1时,满足条件并且k递增并变为N,然后它尝试访问超出范围的lists[N],因此出现错误。 将其固定为:

    while( k < N && lists[k] == NULL )
                ++k;
    

    现在可以了,谢谢你的回答:)

    【讨论】:

      【解决方案3】:

      如果我理解这个要求,当所有成员都按升序排列时,您希望将所有列表合并到一个输出列表中。

      #include <list>
      #include <vector>
      #include <map>
      
      // 'Merge' function:
      
      std::list<int> merge(std::vector<std::list<int>>& rlists)
      {
          std::map<int, int> map;
          for (auto list : rlists)
              for (auto i : list)
                  map[i]++;
      
          std::list<int> onelist;
          for (auto item : map)
              for (int i = item.second; i > 0; i--)
                  onelist.push_back(item.first);
      
          return onelist;
      }
      
      //////////////// Use Case: ////////////////
      
      int main()
      {
          std::vector<std::list<int>> lists;
      
          lists.push_back(std::list<int>{ 1, 4, 5 });
          lists.push_back(std::list<int>{}); // Empty
          lists.push_back(std::list<int>{ 1, 3, 4 });
          lists.push_back(std::list<int>{ 2, 6 });
      
          std::list<int> onelist(merge(lists));
      }
      

      【讨论】:

        猜你喜欢
        • 2021-07-01
        • 2019-03-20
        • 2011-05-17
        • 2019-12-11
        • 1970-01-01
        • 2018-05-16
        • 1970-01-01
        • 1970-01-01
        • 2019-12-07
        相关资源
        最近更新 更多