diff --git a/DIRECTORY.md b/DIRECTORY.md index 6f63a88b085a..6e985fe2f799 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -156,6 +156,7 @@ * [SearchSinglyLinkedListRecursion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/SearchSinglyLinkedListRecursion.java) * [SinglyLinkedList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/SinglyLinkedList.java) * [SkipList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/SkipList.java) + * [SortedLinkedList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/SortedLinkedList.java) * [Node](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/Node.java) * queues * [CircularQueue](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/queues/CircularQueue.java) @@ -268,6 +269,7 @@ * [FractionalKnapsack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/FractionalKnapsack.java) * [GaleShapley](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/GaleShapley.java) * [JobSequencing](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/JobSequencing.java) + * [MergeIntervals](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/MergeIntervals.java) * [MinimizingLateness](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/MinimizingLateness.java) * io * [BufferedReader](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/io/BufferedReader.java) @@ -451,6 +453,8 @@ * [TowerOfHanoi](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/TowerOfHanoi.java) * [TwoPointers](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/TwoPointers.java) * [Verhoeff](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/Verhoeff.java) + * Recursion + * [GenerateSubsets](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/Recursion/GenerateSubsets.java) * scheduling * [FCFSScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/FCFSScheduling.java) * [PreemptivePriorityScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/PreemptivePriorityScheduling.java) @@ -500,7 +504,6 @@ * [CombSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/CombSort.java) * [CountingSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/CountingSort.java) * [CycleSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/CycleSort.java) - * [DNFSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/DNFSort.java) * [DualPivotQuickSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/DualPivotQuickSort.java) * [DutchNationalFlagSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/DutchNationalFlagSort.java) * [ExchangeSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/ExchangeSort.java) @@ -685,6 +688,7 @@ * [RotateSinglyLinkedListsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/RotateSinglyLinkedListsTest.java) * [SinglyLinkedListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/SinglyLinkedListTest.java) * [SkipListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/SkipListTest.java) + * [SortedLinkedListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/SortedLinkedListTest.java) * queues * [CircularQueueTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/queues/CircularQueueTest.java) * [DequeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/queues/DequeTest.java) @@ -754,6 +758,7 @@ * [FractionalKnapsackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/FractionalKnapsackTest.java) * [GaleShapleyTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/GaleShapleyTest.java) * [JobSequencingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/JobSequencingTest.java) + * [MergeIntervalsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/MergeIntervalsTest.java) * [MinimizingLatenessTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/MinimizingLatenessTest.java) * io * [BufferedReaderTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/io/BufferedReaderTest.java) @@ -893,6 +898,8 @@ * [TestPrintMatrixInSpiralOrder](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/TestPrintMatrixInSpiralOrder.java) * [TwoPointersTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/TwoPointersTest.java) * [WorstFitCPUTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/WorstFitCPUTest.java) + * Recursion + * [GenerateSubsetsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/Recursion/GenerateSubsetsTest.java) * scheduling * [FCFSSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/FCFSSchedulingTest.java) * [PreemptivePrioritySchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/PreemptivePrioritySchedulingTest.java) diff --git a/src/main/java/com/thealgorithms/greedyalgorithms/MergeIntervals.java b/src/main/java/com/thealgorithms/greedyalgorithms/MergeIntervals.java new file mode 100644 index 000000000000..07bd0b73326f --- /dev/null +++ b/src/main/java/com/thealgorithms/greedyalgorithms/MergeIntervals.java @@ -0,0 +1,64 @@ +package com.thealgorithms.greedyalgorithms; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Problem Statement: + * Given an array of intervals where intervals[i] = [starti, endi]. + * + * Merge all overlapping intervals and return an array of the non-overlapping + * intervals + * that cover all the intervals in the input. + */ +public final class MergeIntervals { + + /** + * Private constructor to prevent instantiation of this utility class. + */ + private MergeIntervals() { + } + + /** + * Merges overlapping intervals from the given array of intervals. + * + * The method sorts the intervals by their start time, then iterates through the + * sorted intervals + * and merges overlapping intervals. If an interval overlaps with the last + * merged interval, + * it updates the end time of the last merged interval. Otherwise, it adds the + * interval as a new entry. + * + * @param intervals A 2D array representing intervals where each element is an + * interval [starti, endi]. + * @return A 2D array of merged intervals where no intervals overlap. + * + * Example: + * Input: {{1, 3}, {2, 6}, {8, 10}, {15, 18}} + * Output: {{1, 6}, {8, 10}, {15, 18}} + */ + public static int[][] merge(int[][] intervals) { + // Sort the intervals by their start time (ascending order) + Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0])); + + // List to store merged intervals + List merged = new ArrayList<>(); + + for (int[] interval : intervals) { // Each interval + // If the merged list is empty or the current interval does not overlap with + // the last merged interval, add it to the merged list. + if (merged.isEmpty() || interval[0] > merged.get(merged.size() - 1)[1]) { + merged.add(interval); + } else { + // If there is an overlap, merge the intervals by updating the end time + // of the last merged interval to the maximum end time between the two + // intervals. + merged.get(merged.size() - 1)[1] = Math.max(merged.get(merged.size() - 1)[1], interval[1]); + } + } + + // Convert the list of merged intervals back to a 2D array and return it + return merged.toArray(new int[merged.size()][]); + } +} diff --git a/src/test/java/com/thealgorithms/greedyalgorithms/MergeIntervalsTest.java b/src/test/java/com/thealgorithms/greedyalgorithms/MergeIntervalsTest.java new file mode 100644 index 000000000000..0135f9d73260 --- /dev/null +++ b/src/test/java/com/thealgorithms/greedyalgorithms/MergeIntervalsTest.java @@ -0,0 +1,71 @@ +package com.thealgorithms.greedyalgorithms; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +import org.junit.jupiter.api.Test; + +public class MergeIntervalsTest { + + @Test + public void testMergeIntervalsWithOverlappingIntervals() { + // Test case where some intervals overlap and should be merged + int[][] intervals = {{1, 3}, {2, 6}, {8, 10}, {15, 18}}; + int[][] expected = {{1, 6}, {8, 10}, {15, 18}}; + int[][] result = MergeIntervals.merge(intervals); + assertArrayEquals(expected, result); + } + + @Test + public void testMergeIntervalsWithNoOverlap() { + // Test case where intervals do not overlap + int[][] intervals = {{1, 2}, {3, 4}, {5, 6}}; + int[][] expected = {{1, 2}, {3, 4}, {5, 6}}; + int[][] result = MergeIntervals.merge(intervals); + assertArrayEquals(expected, result); + } + + @Test + public void testMergeIntervalsWithCompleteOverlap() { + // Test case where intervals completely overlap + int[][] intervals = {{1, 5}, {2, 4}, {3, 6}}; + int[][] expected = {{1, 6}}; + int[][] result = MergeIntervals.merge(intervals); + assertArrayEquals(expected, result); + } + + @Test + public void testMergeIntervalsWithSingleInterval() { + // Test case where only one interval is given + int[][] intervals = {{1, 2}}; + int[][] expected = {{1, 2}}; + int[][] result = MergeIntervals.merge(intervals); + assertArrayEquals(expected, result); + } + + @Test + public void testMergeIntervalsWithEmptyArray() { + // Test case where the input array is empty + int[][] intervals = {}; + int[][] expected = {}; + int[][] result = MergeIntervals.merge(intervals); + assertArrayEquals(expected, result); + } + + @Test + public void testMergeIntervalsWithIdenticalIntervals() { + // Test case where multiple identical intervals are given + int[][] intervals = {{1, 3}, {1, 3}, {1, 3}}; + int[][] expected = {{1, 3}}; + int[][] result = MergeIntervals.merge(intervals); + assertArrayEquals(expected, result); + } + + @Test + public void testMergeIntervalsWithRandomIntervals() { + // Test case with a mix of overlapping and non-overlapping intervals + int[][] intervals = {{1, 4}, {5, 7}, {2, 6}, {8, 10}}; + int[][] expected = {{1, 7}, {8, 10}}; + int[][] result = MergeIntervals.merge(intervals); + assertArrayEquals(expected, result); + } +}