Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit fc4d94f

Browse files
authored
Merge pull request #12 from borrelunde/problem_0436_find_right_interval
LeetCode problem: 436. Find Right Interval
2 parents 26a0855 + 7cd3cc9 commit fc4d94f

File tree

3 files changed

+299
-0
lines changed

3 files changed

+299
-0
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# 436. Find Right Interval
2+
3+
Difficulty: `Medium`
4+
Topics: `Array`, `Binary Search`, `Sorting`
5+
6+
You are given an array of `intervals`, where `intervals[i] = [start_i, end_i]` and each `start_i` is **unique**.
7+
8+
The **right interval** for an interval `i` is an interval `j` such that `start_j >= end_i` and `start_j` is
9+
**minimized**. Note that `i` may equal `j`.
10+
11+
Return *an array of **right interval** indices for each interval `i`*. If no **right interval** exists for interval `i`,
12+
then put `-1` at index `i`.
13+
14+
**Example 1:**
15+
16+
```text
17+
Input: intervals = [[1,2]]
18+
Output: [-1]
19+
Explanation: There is only one interval in the collection, so it outputs -1.
20+
```
21+
22+
**Example 2:**
23+
24+
```text
25+
Input: intervals = [[3,4],[2,3],[1,2]]
26+
Output: [-1,0,1]
27+
Explanation: There is no right interval for [3,4].
28+
The right interval for [2,3] is [3,4] since start_0 = 3 is the smallest start that is >= end_1 = 3.
29+
The right interval for [1,2] is [2,3] since start_1 = 2 is the smallest start that is >= end_2 = 2.
30+
```
31+
32+
**Example 3:**
33+
34+
```text
35+
Input: intervals = [[1,4],[2,3],[3,4]]
36+
Output: [-1,2,-1]
37+
Explanation: There is no right interval for [1,4] and [3,4].
38+
The right interval for [2,3] is [3,4] since start_2 = 3 is the smallest start that is >= end_1 = 3.
39+
```
40+
41+
**Constraints:**
42+
43+
- `1 <= intervals.length <= 2 * 10^4`
44+
- `intervals[i].length == 2`
45+
- `-10^6 <= start_i <= end_i <= 10^6`
46+
- The start point of each interval is **unique**.
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package com.borrelunde.leetcodesolutions.problem0436.findrightinterval;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
6+
/**
7+
* This is the solution to the LeetCode problem: 436. Find Right Interval
8+
*
9+
* @author Børre A. Opedal Lunde
10+
* @since 2024.02.09
11+
*/
12+
public class Solution {
13+
14+
private static final int INVALID_INDEX = - 1;
15+
16+
public int[] findRightInterval(int[][] intervals) {
17+
18+
// Map to store the start value and index of each interval.
19+
Map<Integer, Integer> intervalStartValueByIndex = new HashMap<>();
20+
for (int i = 0; i < intervals.length; i++) {
21+
intervalStartValueByIndex.put(intervals[i][0], i);
22+
}
23+
24+
// Sort the intervals so that a binary search can be used on it.
25+
sort(intervals);
26+
27+
// The array to store the right interval indices.
28+
int[] result = new int[intervals.length];
29+
30+
// Find the right interval for each interval.
31+
for (int[] interval : intervals) {
32+
int intervalIndex = intervalStartValueByIndex.get(interval[0]);
33+
int rightIntervalIndex = binarySearch(intervals, interval[1]);
34+
result[intervalIndex] = rightIntervalIndex == INVALID_INDEX
35+
? INVALID_INDEX
36+
: intervalStartValueByIndex.get(intervals[rightIntervalIndex][0]);
37+
}
38+
39+
// Return the right interval indices array.
40+
return result;
41+
}
42+
43+
private static int binarySearch(int[][] intervals, int target) {
44+
45+
int low = 0;
46+
int high = intervals.length - 1;
47+
48+
while (low <= high) {
49+
// Calculate the middle index of the array. Bitwise shift to the
50+
// right is the same as dividing by 2, but faster.
51+
int middle = low + ((high - low) >> 1);
52+
53+
if (intervals[middle][0] >= target) {
54+
high = middle - 1;
55+
} else {
56+
low = middle + 1;
57+
}
58+
}
59+
60+
// After the loop, low is the smallest index of the interval whose start
61+
// value is greater than or equal to the target. However, we need to
62+
// check if it is within the bounds of the array. If it is not, then
63+
// the target was not found.
64+
65+
return low < intervals.length ? low : INVALID_INDEX;
66+
}
67+
68+
private static void sort(int[][] matrix) {
69+
70+
// A temporary matrix is used in the sorting algorithm to store sorted
71+
// elements before it is copied to the original matrix.
72+
int[][] tempMatrix = new int[matrix.length][2];
73+
74+
// Start the recursive merge-sorting process.
75+
mergeSort(matrix, tempMatrix, 0, matrix.length - 1);
76+
}
77+
78+
private static void mergeSort(int[][] matrix, int[][] tempMatrix, int low, int high) {
79+
80+
// If the matrix has 0 or 1 elements, it's already sorted.
81+
if (low >= high) {
82+
return; // Break out of recursion.
83+
}
84+
85+
// Calculate the middle index of the array. Bitwise shift to the right
86+
// is the same as dividing by 2, but faster.
87+
int middle = low + ((high - low) >> 1);
88+
mergeSort(matrix, tempMatrix, low, middle); // Sort the left half.
89+
mergeSort(matrix, tempMatrix, middle + 1, high); // Sort the right half.
90+
merge(matrix, tempMatrix, low, middle, high); // Merge the two sorted halves.
91+
}
92+
93+
private static void merge(int[][] matrix, int[][] tempMatrix, int low, int middle, int high) {
94+
95+
// Indices for left and right halves, and the temporary helper matrix.
96+
int left = low;
97+
int right = middle + 1;
98+
int temp = 0;
99+
100+
// Merge left and right halves into the temporary matrix.
101+
while (left <= middle && right <= high) {
102+
if (matrix[left][0] <= matrix[right][0]) {
103+
tempMatrix[temp++] = matrix[left++];
104+
} else {
105+
tempMatrix[temp++] = matrix[right++];
106+
}
107+
}
108+
109+
// If there are remaining elements in the left half, copy them into the
110+
// temporary matrix.
111+
while (left <= middle) {
112+
tempMatrix[temp++] = matrix[left++];
113+
}
114+
115+
// The same goes for the right half.
116+
while (right <= high) {
117+
tempMatrix[temp++] = matrix[right++];
118+
}
119+
120+
// Finally, copy the sorted elements from the temporary matrix to the
121+
// original matrix.
122+
for (int i = 0; i < temp; i++) {
123+
matrix[low + i] = tempMatrix[i];
124+
}
125+
}
126+
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package com.borrelunde.leetcodesolutions.problem0436.findrightinterval;
2+
3+
import org.junit.jupiter.api.DisplayName;
4+
import org.junit.jupiter.api.Test;
5+
6+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
7+
8+
/**
9+
* This is the test to the LeetCode problem: 463. Find Right Interval
10+
*
11+
* @author Børre A. Opedal Lunde
12+
* @since 2024.02.09
13+
*/
14+
@DisplayName("Find Right Interval")
15+
class SolutionTest {
16+
17+
private final Solution solution = new Solution();
18+
19+
@Test
20+
@DisplayName("Example one")
21+
void exampleOne() {
22+
int[][] intervals = new int[][]{
23+
{1, 2}
24+
};
25+
26+
int[] expected = new int[]{- 1};
27+
int[] actual = solution.findRightInterval(intervals);
28+
29+
assertArrayEquals(expected, actual);
30+
}
31+
32+
@Test
33+
@DisplayName("Example two")
34+
void exampleTwo() {
35+
int[][] intervals = new int[][]{
36+
{3, 4},
37+
{2, 3},
38+
{1, 2}
39+
};
40+
41+
int[] expected = new int[]{- 1, 0, 1};
42+
int[] actual = solution.findRightInterval(intervals);
43+
44+
assertArrayEquals(expected, actual);
45+
}
46+
47+
@Test
48+
@DisplayName("Example three")
49+
void exampleThree() {
50+
int[][] intervals = new int[][]{
51+
{1, 4},
52+
{2, 3},
53+
{3, 4}
54+
};
55+
56+
int[] expected = new int[]{- 1, 2, - 1};
57+
int[] actual = solution.findRightInterval(intervals);
58+
59+
assertArrayEquals(expected, actual);
60+
}
61+
62+
@Test
63+
@DisplayName("Empty matrix")
64+
void emptyMatrix() {
65+
int[][] intervals = new int[][]{
66+
// Empty.
67+
};
68+
69+
int[] expected = new int[]{};
70+
int[] actual = solution.findRightInterval(intervals);
71+
72+
assertArrayEquals(expected, actual);
73+
}
74+
75+
@Test
76+
@DisplayName("Large interval that encompasses others")
77+
void largeIntervalEncompassesOthers() {
78+
int[][] intervals = {
79+
{1, 100},
80+
{2, 3},
81+
{4, 5},
82+
{6, 7}
83+
};
84+
int[] expected = {- 1, 2, 3, - 1};
85+
int[] actual = solution.findRightInterval(intervals);
86+
assertArrayEquals(expected, actual);
87+
}
88+
89+
@Test
90+
@DisplayName("Non-overlapping, consecutive intervals")
91+
void nonOverlappingConsecutiveIntervals() {
92+
int[][] intervals = {
93+
{1, 2},
94+
{2, 3},
95+
{3, 4}
96+
};
97+
int[] expected = {1, 2, - 1};
98+
int[] actual = solution.findRightInterval(intervals);
99+
assertArrayEquals(expected, actual);
100+
}
101+
102+
@Test
103+
@DisplayName("Reverse ordered intervals")
104+
void reverseOrderedIntervals() {
105+
int[][] intervals = {
106+
{3, 4},
107+
{2, 3},
108+
{1, 2}
109+
};
110+
int[] expected = {- 1, 0, 1};
111+
int[] actual = solution.findRightInterval(intervals);
112+
assertArrayEquals(expected, actual);
113+
}
114+
115+
@Test
116+
@DisplayName("Intervals with large numbers")
117+
void intervalsWithLargeNumbers() {
118+
int[][] intervals = {
119+
{1000000, 2000000},
120+
{2000000, 3000000},
121+
{3000000, 4000000}
122+
};
123+
int[] expected = {1, 2, - 1};
124+
int[] actual = solution.findRightInterval(intervals);
125+
assertArrayEquals(expected, actual);
126+
}
127+
}

0 commit comments

Comments
 (0)