leetcode 436. Find Right Interval

56 篇文章 0 订阅
53 篇文章 0 订阅

题目描述

Given a set of intervals, for each of the interval i, check if there exists an interval j whose start point is bigger than or equal to the end point of the interval i, which can be called that j is on the “right” of i.

For any interval i, you need to store the minimum interval j’s index, which means that the interval j has the minimum start point to build the “right” relationship for interval i. If the interval j doesn’t exist, store -1 for the interval i. Finally, you need output the stored value of each interval as an array.

Note:
You may assume the interval’s end point is always bigger than its start point.
You may assume none of these intervals have the same start point.
Example 1:
Input: [ [1,2] ]

Output: [-1]

Explanation: There is only one interval in the collection, so it outputs -1.
Example 2:
Input: [ [3,4], [2,3], [1,2] ]

Output: [-1, 0, 1]

Explanation: There is no satisfied “right” interval for [3,4].
For [2,3], the interval [3,4] has minimum-“right” start point;
For [1,2], the interval [2,3] has minimum-“right” start point.
Example 3:
Input: [ [1,4], [2,3], [3,4] ]

Output: [-1, 2, -1]

Explanation: There is no satisfied “right” interval for [1,4] and [3,4].
For [2,3], the interval [3,4] has minimum-“right” start point.

解题思路

这道题初读有些绕口,其实简单点说,有一个由“间隔”构成的数组(所谓的“间隔”,就是一对升序排列的数),对于每一个间隔,找到另一个间隔,它满足这样的关系:该间隔的左侧结点大于先前间隔的右侧结点,我们称这样的间隔为右侧间隔(right interval),这样的右侧间隔可能有多个,返回其中左侧值最小的间隔的下标,若不存在这样的右侧间隔,则返回-1.

很容易想到排序。这也是遇到此类问题的一个正常思路,我们希望按某个序排好的数组具备某些满足题目要求的性质,从而能够从这个数组中得到最终解。一个简单的考虑:按start(左侧值)或end(右侧值)排序(先不考虑下标问题,下标可以以某种方式记录)。我们分别思考这两种排序对应的情况:
1 start排序。
start方式的排序按照start从小到大重新排序序列。我们思考这样做得到的结果:我们知道,我们要求end对应的第一个大于end的左侧start,那么这样的排序显然合理,出现在右侧的大于该end的start一定是要求的第一个start,我们只需遍历新数组即可。
2 end排序。
end方式的排序按照end从小到大排序序列。对于数组中的每一个序列,我们能够知道的只是下个end是大于当前间隔的end的,但是我们无从得知start与end的关系,这样得到的关系更像是一个左侧关系(find left interval),该间隔右侧的第一个end一定是大于左侧start的第一个end,这与题目要求并不符合。

实现思路:
我们需要一个新的数据结构保存interval和他们的初始位置下标,生成一个新数组并进行排序,关于该思路的优化操作会在第二种实现中说明。

/**
 * Definition for an interval.
 * struct Interval {
 *     int start;
 *     int end;
 *     Interval() : start(0), end(0) {}
 *     Interval(int s, int e) : start(s), end(e) {}
 * };
 */
struct Wrapper{
    Interval inter;
    int pos;
    Wrapper(Interval i,int p):inter(i),pos(p){};
};
class Solution {
public:


    int findPos(vector<Wrapper>& mWrapper,vector<Wrapper>::iterator fIter) {
        if(fIter+1==mWrapper.end()) return -1;
        auto left = fIter+1;
        auto right = mWrapper.end()-1;
        while(left<right) {
            auto mid = left+(right-left)/2;
            if(mid->inter.start==fIter->inter.end) return mid->pos;
            if(mid->inter.start>fIter->inter.end) right = mid;
            else left = mid+1;
        }
        if(left->inter.start>=fIter->inter.end) return left->pos;
        return -1;
    }
    vector<int> findRightInterval(vector<Interval>& intervals) {


        vector<Wrapper> mWrapper;
        for(int i = 0;i<intervals.size();++i) {
            mWrapper.emplace_back(Wrapper(intervals[i],i));
        }
        auto cmp = [](const Wrapper&lhs, const Wrapper&rhs)->int{
           return lhs.inter.start<rhs.inter.start; 
        };
        sort(mWrapper.begin(),mWrapper.end(),cmp);
        vector<int> retVec(intervals.size(),-1);
        auto iter = mWrapper.begin();
        for(;iter!=mWrapper.end();iter++) {
            retVec[iter->pos] = findPos(mWrapper,iter);
        }
        return retVec;
        }
 };

从最后的统计结果来看,这种解法的速度超过了91%的cpp提交,从速度的角度考虑无疑已经达到了最优,但是一个令人烦躁的问题就在于,我们甚至需要对自定义的数据结构定义一个lambda(当然也可以是其它可调用对象)来完成排序工作,此外,我们仍需自己实现二分查找函数,来进行查找加速(否则,很容易出现超时情况)。这种写法无疑是我们必须掌握的解法。然而,在思想确定的情况下,多利用stl库可能更有利于在面试过程中快速拿下本题。下面将要介绍的解法利用了map数据结构来解这道题,我们知道,map中的数据是按照key进行字典排序的,也就是说,我们只需要遍历一遍该数组,就可以得到一个按start排序的map,之后,我们只需要在map中进行二分查找(利用stl lower_bound)就可以找到答案。这种解法,无疑是要比上述解法慢的,map的插入时间,整体二分查找的耗时,都是时间消耗所在,但是这种解法胜在写法简单,可以快速AC。

vector<int> findRightInterval(vector<Interval>& intervals) {
        map<int,int> iMap;
        vector<int> retVec;
        for(int i = 0;i<intervals.size();++i) {
            iMap[intervals[i].start] = i;
        }
        for(auto&val:intervals) {
            auto iter = iMap.lower_bound(val.end);
            if(iter!=iMap.end()) {
                retVec.push_back(iter->second);
            }else {
                retVec.push_back(-1);
            }
        }
        return retVec;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值