为什么自定义比较器时出现有关空指针的错误 根据Pete的建议进行编辑:

问题描述

我正在尝试通过Leetcode解决此问题:https://leetcode.com/problems/merge-intervals

给出间隔的集合,合并所有重叠的间隔。

示例1:

Input: intervals = [[1,3],[2,6],[8,10],[15,18]]
Output: [[1,18]]
Explanation: Since intervals [1,3] and [2,6] overlaps,merge them into [1,6].

示例2:

Input: intervals = [[1,4],[4,5]]
Output: [[1,5]]
Explanation: Intervals [1,4] and [4,5] are considered overlapping.

注意:输入类型已于2019年4月15日更改。请重置为代码定义以获取新的方法签名。

约束:

intervals[i][0] <= intervals[i][1]

我只是有一个简单的主意:对输入进行排序并进行合并。

这是我的代码

vector<vector<int>> merge(vector<vector<int>> &intervals)
{
    vector<vector<int>> res;
    if (intervals.empty()) {
        return res;
    }
    std::sort(intervals.begin(),intervals.end(),[](const vector<int> e1,const vector<int> e2) {
        if (e1[0] == e2[0]) {
            return e1[1] <= e2[1];     // ERROR!!!
        }
        return e1[0] < e2[0];
    });
    res.push_back(intervals[0]);
    for (size_t i = 1; i < intervals.size(); i++) {
        if (res.back()[1] >= intervals[i][0]) {
            if (res.back()[1] <= intervals[i][1]) {
                res.back()[1] = intervals[i][1];
            }
        } else {
            res.push_back(intervals[i]);
        }

    }
    return res;
}

实际上,错误来自std::sort行。

当我在Leetcode上执行代码时,出现错误

Line 1052: Char 9: runtime error: reference binding to null pointer of type 'const __gnu_cxx::__alloc_traits<std::allocator<int>,int>::value_type' (aka 'const int') (stl_vector.h)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_vector.h:1061:9

但是如果我按如下方式更改比较器:

std::sort(intervals.begin(),const vector<int> e2) {
    if (e1[0] == e2[0]) {
        return e1[1] < e2[1];    // change <= into <
    }
    return e1[0] < e2[0];
});

它将按预期运行,没有任何错误

我不知道为什么。

解决方法

在您的比较器中,此比较:

return e1[1] <= e2[1];

对要比较的元素不满足严格弱排序的要求。例如如果

e1: {1,2}
e2: {1,2}

然后比较e1e2将返回true,而不考虑比较顺序。

违反std::sort的此要求将导致未定义的行为。在这种情况下,UB消毒剂会为您帮助诊断问题。

另一方面,这种比较:

return e1[1] < e2[1];

非常好,因为它会根据需要建立严格弱排序

,
  • 看起来不错!快到了!

  • 我们将执行常规的std::sort()然后使用std::min()std::max(),而不必使用比较器:

// Most of headers are already included;
// Can be removed;
#include <iostream>
#include <cstdint>
#include <vector>

// The following block might slightly improve the execution time;
// Can be removed;
static const auto improve_runtime = []() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    return 0;
}();



struct Solution {
    static const std::vector<std::vector<int>> merge(
            std::vector<std::vector<int>>& intervals
    ) {
        std::sort(std::begin(intervals),std::end(intervals));
        std::vector<std::vector<int>> merged;

        if (std::size(intervals) >= 1) {
            merged.emplace_back(intervals[0]);
        }

        for (std::size_t index = 0; index < std::size(intervals); ++index) {
            const std::vector<int> interval = intervals[index];
            const std::vector<int> tail = merged.back();

            if (tail[1] >= interval[0]) {
                merged.pop_back();
                merged.emplace_back(std::vector<int> {
                    std::min(tail[0],interval[0]),std::max(interval[1],tail[1])
                });

            } else {
                merged.emplace_back(interval);
            }
        }

        return merged;
    }

};


// int main() {
//     std::vector<std::vector<int>> intervals = {{1,3},{2,6},{8,10},{15,18}};
//     std::vector<std::vector<int>> merged = Solution().merge(intervals);

//     for (auto& interval : merged) {
//         std::cout << "[" << interval[0] << "\t" << interval[1] << "]\n";
//     }
// }

PS:

  • LeetCode在C ++ 17上运行。
  • 除了比赛外,还要确保始终使用std::

  • 这是您的有效算法,无需使用比较器:
// Most of headers are already included;
// Can be removed;
#include <iostream>
#include <cstdint>
#include <vector>

// The following block might slightly improve the execution time;
// Can be removed;
static const auto improve_runtime = []() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    return 0;
}();


struct Solution {
    std::vector<std::vector<int>> merge(
                                   std::vector<std::vector<int>>& intervals
    ) {
        std::vector<std::vector<int>> res;

        if (intervals.empty()) {
            return res;
        }

        std::sort(intervals.begin(),intervals.end());

        res.push_back(intervals[0]);

        for (std::size_t i = 1; i < intervals.size(); i++) {
            if (res.back()[1] >= intervals[i][0]) {
                if (res.back()[1] <= intervals[i][1]) {
                    res.back()[1] = intervals[i][1];
                }

            } else {
                res.push_back(intervals[i]);
            }

        }

        return res;
    }

};


int main() {
    std::vector<std::vector<int>> intervals = {{1,18}};
    std::vector<std::vector<int>> merged = Solution().merge(intervals);

    for (auto& interval : merged) {
        std::cout << "[" << interval[0] << "\t" << interval[1] << "]\n";
    }
}

根据Pete的建议进行编辑:

包含两个连续下划线( optimize )和 以下划线和大写字母开头的名称是 保留供实现使用。不要在您的代码中使用它们。