前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >leetcode436. Find Right Interval

leetcode436. Find Right Interval

作者头像
眯眯眼的猫头鹰
发布2019-07-15 17:33:12
4870
发布2019-07-15 17:33:12
举报

题目要求

代码语言:javascript
复制
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.
NOTE: input types have been changed on April 15, 2019. Please reset to default code definition to get new method signature.

假设一个二维的整数数组中每一行表示一个区间,每一行的第一个值表示区间的左边界,第二个值表示区间的右边界。现在要求返回一个整数数组,用来记录每一个边界右侧最邻近的区间。

[ [1,4], [2,3], [3,4] ]表示三个区间,[1,4]不存在最邻近右区间,因此[1,4]的最邻近右区间的位置为-1。[2,3]最邻近右区间为[3,4],因此返回2,[3,4]也不存在最临近右区间,因此也返回-1。最终函数返回数组[-1,2,-1]。

思路1:二分法

如果我们将区间按照左边界进行排序,则针对每一个区间的右边界,只要找到左边界比这个值大的最小左边界所在的区间即可。这里不能够直接对原来的二维数组进行排序,因为会丢失每一个区间的原始下标位置。代码中采用了内部类Node来记录每一个区间的左边界以及每一个区间的原始下标,并对Node进行排序和二分法查找。代码如下:

代码语言:javascript
复制
    public int[] findRightInterval(int[][] intervals) {        
        int[] result = new int[intervals.length];
        Arrays.fill(result, -1);
        
        Node[] leftIndex = new Node[intervals.length];
        for(int i = 0 ; i<intervals.length ; i++) {
            Node n = new Node();
            n.index = i;
            n.value = intervals[i][0];
            leftIndex[i] = n;
        }
        Arrays.sort(leftIndex);
        
        for(int i = 0 ; i<intervals.length ; i++) {
            int rightIndex = intervals[i][1];
            int left = 0, right = intervals.length-1;
            while(left <=right) {
                int mid = (left + right) / 2;
                Node tmp = leftIndex[mid];
                if(tmp.value > rightIndex) {
                    right = mid - 1;
                }else {
                    left = mid + 1;
                }
            }
            if(leftIndex[right].value == rightIndex) {
                result[i] = leftIndex[right].index;
            }else if(right<intervals.length-1) {
                result[i] = leftIndex[right+1].index;
            }
            
        }
        return result;
    }
    
    public static class Node implements Comparable<Node>{
        int value;
        int index;
        @Override
        public int compareTo(Node o) {
            // TODO Auto-generated method stub
            return this.value - o.value;
        }
    }

思路二:桶排序

换一种思路,有没有办法将所有的区间用一维数组的方式展开,一维数组的每一个下标上的值,都记录了该位置所在的右侧第一个区间。具体流程如下:

  1. 假设输入为[3,4], [2,3], [1,2]的三个区间,展开来后我们知道这里的三个区间横跨了[1,4]这么一个区间
  2. 我们可以用长度为4的一维数组bucket来表示这个完整的区间,其中每一个下标代表的位置都以左边界作为偏移值,如数组的0下标其实代表位置1,数组的1下标代表位置2。
  3. 先根据所有区间的左值更新区间数组,如[3,4]代表着区间数组中位置为3-1=2的位置的第一个右侧区间为[3,4], 因此bucket[2]=0, 同理bucket[1]=0, bucket[0]=1
  4. 开始查询时,如果当前桶下标上没有记录右侧的第一个区间,则不停的向右遍历,直到找到第一个值。如果没找到,则说明其右侧不存在区间了。反过来,也可以从右往左遍历bucket数组,每遇到一个没有填充的位置,就将右侧的值赋予当前位置。

代码如下:

代码语言:javascript
复制
    public int[] findRightInterval(int[][] intervals) {
        int[] result = new int[intervals.length];
        int min = intervals[0][0], max = intervals[0][1];
        
        for(int i = 1 ; i<intervals.length ; i++) {
            min = Math.min(min, intervals[i][0]);
            max = Math.max(max, intervals[i][1]);
        }
        
        int[] buckets = new int[max - min + 1];
        Arrays.fill(buckets, -1);
        for(int i = 0 ; i<intervals.length ; i++) {
            buckets[intervals[i][0] - min] = i;
        }
        
        for(int i = buckets.length-2 ; i>=0 ; i--) {
            if(buckets[i] == -1) buckets[i] = buckets[i+1]; 
        }
        
        for(int i = 0 ; i<intervals.length ; i++) {
            result[i] = buckets[intervals[i][1] - min];
        }
        return result;
    }

这里的核心思路在于,如何理解bucket数组,这个bucket数组本质上是将所有的区间以最左边界和最右边界展开,数组的每一个下标对应着区间中的相对位置,并记录了这个下标右侧的第一个区间的位置。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 题目要求
  • 思路1:二分法
  • 思路二:桶排序
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档