LeetCode 436. Find Right Interval
一道需要自定义比较函数的二分查找题。
这里重点展示自定义比较,给出比较函数、比较器、lambda三种写法。
题目描述
You are given an array of intervals, where intervals[i] = [starti, endi] and each starti is unique.
The right interval for an interval i is an interval j such that startj >= endi and startj is minimized.
Return an array of right interval indices for each interval i. If no right interval exists for interval i, then put -1 at index i.
Example 1:
Input: intervals = [[1,2]]
Output: [-1]
Explanation: There is only one interval in the collection, so it outputs -1.
Example 2:
Input: intervals = [[3,4],[2,3],[1,2]]
Output: [-1,0,1]
Explanation: There is no right interval for [3,4].
The right interval for [2,3] is [3,4] since start0 = 3 is the smallest start that is >= end1 = 3.
The right interval for [1,2] is [2,3] since start1 = 2 is the smallest start that is >= end2 = 2.
Example 3:
Input: intervals = [[1,4],[2,3],[3,4]]
Output: [-1,2,-1]
Explanation: There is no right interval for [1,4] and [3,4].
The right interval for [2,3] is [3,4] since start2 = 3 is the smallest start that is >= end1 = 3.
Constraints:
- 1 <= intervals.length <= 2 * 104
- intervals[i].length == 2
- -106 <= starti <= endi <= 106
- The start point of each interval is unique.
解题思路
题目限定了每个时间段的开始时间是唯一的,让我们去找每个结束时间之后的下一个最早的开始时间。
我们可以首先按开始时间进行排序,然后对于每个结束时间,使用二分查找找出开始时间即可。
这里,下一个开始时间可以和当前结束时间相同,所以选用的应该是 lower_bound。
对于从开始时间到原始下标的对应,我们可以单独使用一个map做映射,或者使用pair将开始时间直接和下标打包到一起。为了展示不同类型的自定义比较器写法,我们这里使用第二种方法。
我们可以自定义比较器,根据 cplusplus.com 所说,This can either be a function pointer or a function object。也就是说我们可以传入一个比较函数,或者手写一个 struct
并重载 ()
运算符,当然我们也可以直接使用 lambda
。
cppreference.com 给出了比较器中参数类型的对应关系:
- 第一个参数是容器元素类型;
- 第二个参数是目标元素类型;
为什么要区分两种不同类型呢,因为我们这两种元素可以是不同类型的,如本题中我们的target
是一个int
,而element
是pair<int,int>
或者vector<int>
。
参考代码
lambda写法直接在行内写函数体,比较紧凑,类型也容易对应:
/*
* @lc app=leetcode id=436 lang=cpp
*
* [436] Find Right Interval
*/
// @lc code=start
class Solution {
public:
vector<int> findRightInterval(vector<vector<int>>& intervals) {
assert(!intervals.empty());
size_t n = intervals.size();
vector< pair<int,int> > v(n);
for (int i=0; i<n; i++) {
v[i] = { intervals[i][0], i };
}
sort(v.begin(), v.end());
vector<int> res(n);
for (int i=0; i<n; i++) {
auto it = lower_bound(v.begin(), v.end(), intervals[i][1],
[&](const pair<int,int>& p, const int& target){ return p.first < target; });
if (it != v.end()) {
res[i] = it->second;
} else {
res[i] = -1;
}
}
return res;
} // AC
};
// @lc code=end
或者使用比较函数和比较器,这里只给出需要修改的部分代码:
// 比较函数写法:
static bool cmp(const pair<int,int>& p, const int& target){
return p.first < target;
}
auto it = lower_bound(v.begin(), v.end(), intervals[i][1], cmp); // AC
// 比较器写法:
struct comp {
bool operator()(const pair<int,int>& p, const int& target) {
return p.first < target;
}
};
auto it = lower_bound(v.begin(), v.end(), intervals[i][1], comp()); // AC