leetcode436. 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:

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進行排序和二分法查找。代碼如下:

    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數組,每遇到一個沒有填充的位置,就將右側的值賦予當前位置。

代碼如下:

    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數組本質上是將所有的區間以最左邊界和最右邊界展開,數組的每一個下標對應着區間中的相對位置,並記錄了這個下標右側的第一個區間的位置。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章