找到start比区间i的end大或相等的一个区间 Find Right Interval

问题:

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:

  1. You may assume the interval's end point is always bigger than its start point.
  2. 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.

解决:

① 要求找到start比区间i的end大或相等的一个区间。使用map记录interval及其下标,对interval进行排序,然后查找符合条件的值即可。暴力破解,O(N^2)。

/**
 * Definition for an interval.
 * public class Interval {
 *     int start;
 *     int end;
 *     Interval() { start = 0; end = 0; }
 *     Interval(int s, int e) { start = s; end = e; }
 * }
 */
class Solution { //215ms
    public int[] findRightInterval(Interval[] intervals) {
        int len = intervals.length;
        int[] res = new int[len];
        Arrays.fill(res,-1);
        Map<Interval,Integer> map = new HashMap<>();
        int i = 0;
        for (Interval interval : intervals){
            map.put(interval,i);
            i ++;
        }
        Interval[] tmp = intervals.clone();
        Arrays.sort(tmp, new Comparator<Interval>() {
            @Override
            public int compare(Interval o1, Interval o2) {
                return o1.start - o2.start;
            }
        });
        for (i = 0;i < len - 1;i ++){//在查找方面,可以使用二分查找进行优化,时间复杂度O(nlogn)。
            for (int j = i + 1;j < len;j ++){
                if (tmp[i].end <= tmp[j].start){
                    res[map.get(tmp[i])] = map.get(tmp[j]);
                    break;
                }
            }
        }
        return res;
    }
}

② 使用TreeMap定义的接口。

treemap自带接口方法lowerEntry、floorEntry、ceilingEntry和higherEntry分别返回与小于、小于等于、大于等于、大于给定键的键关联的Map.Entry对象,如果不存在这样的键,则返回null。类似地,方法lowerKey、floorKey、ceilingKey和higherKey只返回关联的键。

class Solution { //54ms
    public int[] findRightInterval(Interval[] intervals) {
        int len = intervals.length;
        int[] res = new int[len];
        TreeMap<Integer,Integer> map = new TreeMap<>();
        for (int i = 0;i < len;i ++){
            map.put(intervals[i].start,i);//建立interval的start与下标之间的映射关系
        }
        for (int i = 0;i < intervals.length;i ++){
            Map.Entry<Integer,Integer> entry = map.ceilingEntry(intervals[i].end);//找到满足所有key大于等于当前interval的end的interval
            res[i] = (entry != null) ? entry.getValue() : -1;
        }
        return res;
    }
}

③ 在discuss看到的。将interval映射为有序的一维数组。

class Solution { //7ms
    //此种做法其实并不难!!!关键是我们要把这些interval放在一个一维数组上来考虑
    public int[] findRightInterval(Interval[] intervals) {
        int max = Integer.MIN_VALUE;//标识最大的end
        int min = Integer.MAX_VALUE;//标识最小的start
        for(Interval interval : intervals){
            max = Math.max(max, interval.end);
            min = Math.min(min, interval.start);
        }
        //建立bucket, max是end最大值,min是start最小值,画一个1d的坐标轴
        int[] start = new int[max - min + 1];
        Arrays.fill(start, -1);
        for(int i = 0; i < intervals.length; i ++){//根据start将interval映射到一维数组中
            //每个bucket的index代表距离0点,intervals[i].start - min的interval的index
            start[intervals[i].start - min] = i;
        }
        for(int i = start.length - 2; i >= 0; i--){
            //如果start[i] == -1, 证明没有这种距离的interval 存在,那么最近的一个interval就会是这个interval的下一个以此类推,所以我们需要从后向前循环
            //因为如果从前往后,就无法保证都是rightmost的interval了
            if(start[i] == -1){
                start[i] = start[i + 1];
            }
        }
        int[] result = new int[intervals.length];
        //intervals[i].end - min可以得到这个interval i他到原点的距离,start中存了,start为这个距离的interval的index
        for(int i = 0; i < result.length; i++){
            result[i] = start[intervals[i].end - min];
        }
        return result;
    }
}

转载于:https://my.oschina.net/liyurong/blog/1602128

你可以使用前缀和来解决这个问题。首先,计算出给定数组的前缀和数组,记为prefix_sum。然后,遍历前缀和数组,并使用哈希表来保存每个前缀和对应的索引。 在遍历前缀和数组的过程中,如果当前前缀和可以被n整除,那么整个数组就是一个满足条件的区间,记录它的起始索引和结束索引。否则,如果当前前缀和已经在哈希表中出现过,说明存在一个区间的和可以被n整除,该区间的起始索引为哈希表中上次出现的索引加1,结束索引为当前索引。 最后,根据得到的起始索引和结束索引,即可得到最大区间。 以下是用Python实现的代码示例: ```python def find_max_interval(arr): prefix_sum = [0] * (len(arr) + 1) for i in range(1, len(prefix_sum)): prefix_sum[i] = (prefix_sum[i - 1] + arr[i - 1]) % n max_len = 0 interval_start = 0 interval_end = 0 prefix_sum_hash = {} for i in range(len(prefix_sum)): if prefix_sum[i] == 0: max_len = i interval_start = 0 interval_end = i - 1 elif prefix_sum[i] in prefix_sum_hash: if i - prefix_sum_hash[prefix_sum[i]] > max_len: max_len = i - prefix_sum_hash[prefix_sum[i]] interval_start = prefix_sum_hash[prefix_sum[i]] + 1 interval_end = i - 1 else: prefix_sum_hash[prefix_sum[i]] = i return interval_start, interval_end # 示例 arr = [4, 3, 1, 6, 7] n = 3 start, end = find_max_interval(arr) print("最大区间起始索引:", start) print("最大区间结束索引:", end) ``` 这段代码的时间复杂度为O(n),其中n是给定数组的长度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值