From 59c9d174fcad3e5d0cd525ee222f1f4912c9f304 Mon Sep 17 00:00:00 2001 From: dksifoua Date: Tue, 27 Aug 2024 23:11:42 -0400 Subject: [PATCH] Median of Two Sorted Arrays --- README.md | 3 +- docs/0004-Median-of-Two-Sorted-Arrays.md | 42 +++++++++++++++++++ .../medianoftwosortedarrays/Solution.java | 41 ++++++++++++++++++ .../medianoftwosortedarrays/SolutionTest.java | 30 +++++++++++++ 4 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 docs/0004-Median-of-Two-Sorted-Arrays.md create mode 100644 src/main/java/io/dksifoua/leetcode/medianoftwosortedarrays/Solution.java create mode 100644 src/test/java/io/dksifoua/leetcode/medianoftwosortedarrays/SolutionTest.java diff --git a/README.md b/README.md index 0b30649..3269503 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,8 @@ |------|------------|------------------------------------------------|------------------------------------------------------|---------------------------------------------------------------------------| | 0001 | Easy | Two Sum | Array, HashMap | [solution](./docs/0001-Two-Sum.md) | | 0002 | Medium | Add Two numbers | LinkedList, Recursion | [solution](./docs/0002-Add-Two-Numbers.md) | -| 003 | Medium | Longest Substring Without Repeating Characters | Hash Table, String, Sliding Window | [solution](./docs/0003-Longest-Substring-Without-Repeating-Characters.md) | +| 0003 | Medium | Longest Substring Without Repeating Characters | Hash Table, String, Sliding Window | [solution](./docs/0003-Longest-Substring-Without-Repeating-Characters.md) | +| 0004 | Hard | Median of Two Sorted Arrays | Array, Binary Search, Divide and Conquer | [solution](./docs/0004-Median-of-Two-Sorted-Arrays.md) | | 0011 | Medium | Container With Most Water | Array, Two Pointers, Greedy | [solution](./docs/0011-Container-With-Most-Water.md) | | 0015 | Medium | Three sum | Array, Two Pointers, Sorting | [solution](./docs/0015-Three-Sum.md) | | 0019 | Medium | Remove Nth Node From End Of List | Linked List, Two Pointers | [solution](./docs/0019-Remove-Nth-Node-From-End-Of-List.md) | diff --git a/docs/0004-Median-of-Two-Sorted-Arrays.md b/docs/0004-Median-of-Two-Sorted-Arrays.md new file mode 100644 index 0000000..30f5058 --- /dev/null +++ b/docs/0004-Median-of-Two-Sorted-Arrays.md @@ -0,0 +1,42 @@ +# [Median of Two Sorted Arrays](https://leetcode.com/problems/median-of-two-sorted-arrays/description/) + +## Intuition + +To find the median of two sorted arrays, we can take advantage of their sorted nature and avoid brute force merging and +sorting, which would result in an `O(m+n)` complexity. Instead, we aim to exploit binary search on one of the arrays to +reduce the time complexity to `O(log(min(m, n)))`. The intuition behind this approach is to partition the arrays into +two halves such that the left half contains the smaller elements, and the right half contains the larger elements. This +way, we can directly calculate the median based on the partitioning. + +## Approach + +1. **Recursive Handling of Array Sizes:** The function first ensures that we always perform the binary search on the + smaller array (`nums1`). This ensures the search space is minimized. +2. **Binary Search and Partitioning:** We calculate the middle index for `nums1` and determine the corresponding + partition index for `nums2`. The goal is to ensure that the elements in the left partitions of both arrays are + smaller than the elements in the right partitions. +3. **Conditions to Find the Median:** + - If the largest element in the left partition of `nums1` is smaller than or equal to the smallest element in the + right partition of `nums2`, and vice versa, then we have correctly partitioned the arrays. + - If the total length of both arrays is odd, the median is the maximum of the left partition. + - If the total length is even, the median is the average of the maximum of the left partition and the minimum of the + right partition. +4. **Adjusting the Partition:** If the current partitioning does not meet the conditions, the binary search is adjusted + by either moving the partition in `nums1` to the left or right, depending on the comparison of boundary elements. + +## Complexity + +- **Time Complexity: `O(log(min(m, n)))`**. The binary search is performed on the smaller array, so the time complexity + is logarithmic in the size of the smaller array. +- **Space Complexity: `O(1)`** as no additional space beyond a few variables is used. + +## Code + +- [Java](../src/main/java/io/dksifoua/leetcode/medianoftwosortedarrays/Solution.java) + +## Summary + +This solution uses a binary search technique to find the correct partitioning of two sorted arrays, allowing us to find +the median in `O(log(min(m, n))) time. By focusing on partitioning the arrays into equal halves and ensuring the left +half contains all smaller elements, we can calculate the median without merging the arrays. This method is efficient and +meets the problem’s time complexity requirement. \ No newline at end of file diff --git a/src/main/java/io/dksifoua/leetcode/medianoftwosortedarrays/Solution.java b/src/main/java/io/dksifoua/leetcode/medianoftwosortedarrays/Solution.java new file mode 100644 index 0000000..d5b1a32 --- /dev/null +++ b/src/main/java/io/dksifoua/leetcode/medianoftwosortedarrays/Solution.java @@ -0,0 +1,41 @@ +package io.dksifoua.leetcode.medianoftwosortedarrays; + +public class Solution { + + public double findMedianSortedArrays(int[] nums1, int[] nums2) { + if (nums1.length > nums2.length) { + return this.findMedianSortedArrays(nums2, nums1); + } + + double median = 0d; + int totalLength = nums1.length + nums2.length; + int partitionSize = totalLength % 2 == 0 ? totalLength / 2 : 1 + totalLength / 2; + int leftIndex = 0, rightIndex = nums1.length - 1; + while (true) { + int middleIndex1 = Math.floorDiv(leftIndex + rightIndex, 2); + int middleIndex2 = partitionSize - (middleIndex1 + 1) - 1; + + int leftElement1 = middleIndex1 >= 0 ? nums1[middleIndex1] : Integer.MIN_VALUE; + int leftElement2 = middleIndex2 >= 0 ? nums2[middleIndex2] : Integer.MIN_VALUE; + int rightElement1 = middleIndex1 + 1 < nums1.length ? nums1[middleIndex1 + 1] : Integer.MAX_VALUE; + int rightElement2 = middleIndex2 + 1 < nums2.length ? nums2[middleIndex2 + 1] : Integer.MAX_VALUE; + + if (leftElement1 <= rightElement2 && leftElement2 <= rightElement1) { + if (totalLength % 2 > 0) { + median = Math.max(leftElement1, leftElement2); + } else { + median = (Math.max(leftElement1, leftElement2) + Math.min(rightElement1, rightElement2)) / 2d; + } + break; + } + + if (leftElement1 > rightElement2) { + rightIndex = middleIndex1 - 1; + } else { + leftIndex = middleIndex1 + 1; + } + } + + return median; + } +} diff --git a/src/test/java/io/dksifoua/leetcode/medianoftwosortedarrays/SolutionTest.java b/src/test/java/io/dksifoua/leetcode/medianoftwosortedarrays/SolutionTest.java new file mode 100644 index 0000000..7a1aac2 --- /dev/null +++ b/src/test/java/io/dksifoua/leetcode/medianoftwosortedarrays/SolutionTest.java @@ -0,0 +1,30 @@ +package io.dksifoua.leetcode.medianoftwosortedarrays; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class SolutionTest { + + private final Solution solution = new Solution(); + + @Test + void test1() { + assertEquals(2d, solution.findMedianSortedArrays(new int[] { 1, 3 }, new int[] { 2 })); + } + + @Test + void test2() { + assertEquals(2.5d, solution.findMedianSortedArrays(new int[] { 1, 2 }, new int[] { 3, 4 })); + } + + @Test + void test3() { + assertEquals(1d, solution.findMedianSortedArrays(new int[] {}, new int[] { 1 })); + } + + @Test + void test4() { + assertEquals(-1d, solution.findMedianSortedArrays(new int[] { 3 }, new int[] { -2, -1 })); + } +}