Skip to content

Commit 1173e86

Browse files
committed
feat: update solutions to lc problem: No.0004
No.0004.Median of Two Sorted Arrays
1 parent 80fdd6f commit 1173e86

File tree

6 files changed

+308
-191
lines changed

6 files changed

+308
-191
lines changed

solution/0000-0099/0004.Median of Two Sorted Arrays/README.md

+118-24
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,18 @@
6868

6969
<!-- 这里可写通用的实现逻辑 -->
7070

71+
本题限制了时间复杂度为 `O(log (m+n))`,看到这个时间复杂度,自然而然的想到了应该使用二分查找法来求解。那么回顾一下中位数的定义,如果某个有序数组长度是奇数,那么其中位数就是最中间那个,如果是偶数,那么就是最中间两个数字的平均值。这里对于两个有序数组也是一样的,假设两个有序数组的长度分别为 m 和 n,由于两个数组长度之和 m+n 的奇偶不确定,因此需要分情况来讨论,对于奇数的情况,直接找到最中间的数即可,偶数的话需要求最中间两个数的平均值。为了简化代码,不分情况讨论,我们使用一个小 trick,我们分别找第 `(m+n+1) / 2` 个,和 `(m+n+2) / 2` 个,然后求其平均值即可,这对奇偶数均适用。假如 m+n 为奇数的话,那么其实 `(m+n+1) / 2``(m+n+2) / 2` 的值相等,相当于两个相同的数字相加再除以 2,还是其本身。
72+
73+
这里我们需要定义一个函数来在两个有序数组中找到第 K 个元素,下面重点来看如何实现找到第 K 个元素。
74+
75+
首先,为了避免产生新的数组从而增加时间复杂度,我们使用两个变量 i 和 j 分别来标记数组 nums1 和 nums2 的起始位置。然后来处理一些边界问题,比如当某一个数组的起始位置大于等于其数组长度时,说明其所有数字均已经被淘汰了,相当于一个空数组了,那么实际上就变成了在另一个数组中找数字,直接就可以找出来了。还有就是如果 K=1 的话,那么我们只要比较 nums1 和 nums2 的起始位置 i 和 j 上的数字就可以了。
76+
77+
难点就在于一般的情况怎么处理?因为我们需要在两个有序数组中找到第 K 个元素,为了加快搜索的速度,我们要使用二分法,对 K 二分,意思是我们需要分别在 nums1 和 nums2 中查找第 K/2 个元素,注意这里由于两个数组的长度不定,所以有可能某个数组没有第 K/2 个数字,所以我们需要先检查一下,数组中到底存不存在第 K/2 个数字,如果存在就取出来,否则就赋值上一个整型最大值。如果某个数组没有第 K/2 个数字,那么我们就淘汰另一个数字的前 K/2 个数字即可。有没有可能两个数组都不存在第 K/2 个数字呢,这道题里是不可能的,因为我们的 K 不是任意给的,而是给的 m+n 的中间值,所以必定至少会有一个数组是存在第 K/2 个数字的。
78+
79+
最后是二分法的核心,比较这两个数组的第 K/2 小的数字 midVal1 和 midVal2 的大小,如果第一个数组的第 K/2 个数字小的话,那么说明我们要找的数字肯定不在 nums1 中的前 K/2 个数字,所以我们可以将其淘汰,将 nums1 的起始位置向后移动 K/2 个,并且此时的 K 也自减去 K/2,调用递归。反之,我们淘汰 nums2 中的前 K/2 个数字,并将 nums2 的起始位置向后移动 K/2 个,并且此时的 K 也自减去 K/2,调用递归即可。
80+
81+
> 实际是比较两个数组中的第 K/2 个数字哪一个可能到达最后合并后排序数组中的第 K 个元素的位置,其中小的那个数字注定不可能到达,所以可以直接将小的元素对应的数组的前 K/2 个数字淘汰。
82+
7183
<!-- tabs:start -->
7284

7385
### **Python3**
@@ -77,40 +89,122 @@
7789
```python
7890
class Solution:
7991
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
80-
# concatenate the 2 lists and sort them
81-
nums1 += nums2
82-
nums1.sort()
83-
length = len(nums1)
84-
value = length/2
85-
if length % 2 == 0:
86-
value = int(value)
87-
return (nums1[value-1] + nums1[value])/2
88-
else:
89-
return nums1[int(value)]
92+
def findKth(i, j, k):
93+
if i >= m:
94+
return nums2[j + k - 1]
95+
if j >= n:
96+
return nums1[i + k - 1]
97+
if k == 1:
98+
return min(nums1[i], nums2[j])
99+
midVal1 = nums1[i + k // 2 - 1] if i + k // 2 - 1 < m else float('inf')
100+
midVal2 = nums2[j + k // 2 - 1] if j + k // 2 - 1 < n else float('inf')
101+
if midVal1 < midVal2:
102+
return findKth(i + k // 2, j, k - k // 2)
103+
return findKth(i, j + k // 2, k - k // 2)
104+
105+
m, n = len(nums1), len(nums2)
106+
left, right = (m + n + 1) // 2, (m + n + 2) // 2
107+
return (findKth(0, 0, left) + findKth(0, 0, right)) / 2
90108
```
91109

92110
### **Java**
93111

94112
<!-- 这里可写当前语言的特殊实现逻辑 -->
95113

96114
```java
97-
115+
class Solution {
116+
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
117+
int m = nums1.length;
118+
int n = nums2.length;
119+
int left = (m + n + 1) / 2;
120+
int right = (m + n + 2) / 2;
121+
return (findKth(nums1, 0, nums2, 0, left) + findKth(nums1, 0, nums2, 0, right)) / 2.0;
122+
}
123+
124+
private int findKth(int[] nums1, int i, int[] nums2, int j, int k) {
125+
if (i >= nums1.length) {
126+
return nums2[j + k - 1];
127+
}
128+
if (j >= nums2.length) {
129+
return nums1[i + k - 1];
130+
}
131+
if (k == 1) {
132+
return Math.min(nums1[i], nums2[j]);
133+
}
134+
int midVal1 = (i + k / 2 - 1 < nums1.length) ? nums1[i + k / 2 - 1] : Integer.MAX_VALUE;
135+
int midVal2 = (j + k / 2 - 1 < nums2.length) ? nums2[j + k / 2 - 1] : Integer.MAX_VALUE;
136+
if (midVal1 < midVal2) {
137+
return findKth(nums1, i + k / 2, nums2, j, k - k / 2);
138+
}
139+
return findKth(nums1, i, nums2, j + k / 2, k - k / 2);
140+
}
141+
}
98142
```
99143

100-
### **Nim**
101-
102-
```nim
103-
proc medianOfTwoSortedArrays(nums1: seq[int], nums2: seq[int]): float =
104-
var
105-
fullList: seq[int] = concat(nums1, nums2)
106-
value: int = fullList.len div 2
107-
108-
fullList.sort()
144+
### **C++**
145+
146+
```cpp
147+
class Solution {
148+
public:
149+
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
150+
int m = nums1.size();
151+
int n = nums2.size();
152+
int left = (m + n + 1) / 2;
153+
int right = (m + n + 2) / 2;
154+
return (findKth(nums1, 0, nums2, 0, left) + findKth(nums1, 0, nums2, 0, right)) / 2.0;
155+
}
156+
157+
int findKth(vector<int>& nums1, int i, vector<int>& nums2, int j, int k) {
158+
if (i >= nums1.size()) return nums2[j + k - 1];
159+
if (j >= nums2.size()) return nums1[i + k - 1];
160+
if (k == 1) return min(nums1[i], nums2[j]);
161+
int midVal1 = i + k / 2 - 1 < nums1.size() ? nums1[i + k / 2 - 1] : INT_MAX;
162+
int midVal2 = j + k / 2 - 1 < nums2.size() ? nums2[j + k / 2 - 1] : INT_MAX;
163+
if (midVal1 < midVal2) return findKth(nums1, i + k / 2, nums2, j, k - k / 2);
164+
return findKth(nums1, i, nums2, j + k / 2, k - k / 2);
165+
}
166+
};
167+
```
109168

110-
if fullList.len mod 2 == 0:
111-
result = (fullList[value - 1] + fullList[value]) / 2
112-
else:
113-
result = fullList[value].toFloat()
169+
### **Go**
170+
171+
```go
172+
func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {
173+
m, n := len(nums1), len(nums2)
174+
left, right := (m+n+1)/2, (m+n+2)/2
175+
var findKth func(i, j, k int) int
176+
findKth = func(i, j, k int) int {
177+
if i >= m {
178+
return nums2[j+k-1]
179+
}
180+
if j >= n {
181+
return nums1[i+k-1]
182+
}
183+
if k == 1 {
184+
return min(nums1[i], nums2[j])
185+
}
186+
midVal1 := math.MaxInt32
187+
midVal2 := math.MaxInt32
188+
if i+k/2-1 < m {
189+
midVal1 = nums1[i+k/2-1]
190+
}
191+
if j+k/2-1 < n {
192+
midVal2 = nums2[j+k/2-1]
193+
}
194+
if midVal1 < midVal2 {
195+
return findKth(i+k/2, j, k-k/2)
196+
}
197+
return findKth(i, j+k/2, k-k/2)
198+
}
199+
return (float64(findKth(0, 0, left)) + float64(findKth(0, 0, right))) / 2.0
200+
}
201+
202+
func min(a, b int) int {
203+
if a < b {
204+
return a
205+
}
206+
return b
207+
}
114208
```
115209

116210
### **...**

solution/0000-0099/0004.Median of Two Sorted Arrays/README_EN.md

+108-24
Original file line numberDiff line numberDiff line change
@@ -61,45 +61,129 @@
6161

6262
## Solutions
6363

64+
Binary search.
65+
6466
<!-- tabs:start -->
6567

6668
### **Python3**
6769

6870
```python
6971
class Solution:
7072
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
71-
# concatenate the 2 lists and sort them
72-
nums1 += nums2
73-
nums1.sort()
74-
length = len(nums1)
75-
value = length/2
76-
if length % 2 == 0:
77-
value = int(value)
78-
return (nums1[value-1] + nums1[value])/2
79-
else:
80-
return nums1[int(value)]
73+
def findKth(i, j, k):
74+
if i >= m:
75+
return nums2[j + k - 1]
76+
if j >= n:
77+
return nums1[i + k - 1]
78+
if k == 1:
79+
return min(nums1[i], nums2[j])
80+
midVal1 = nums1[i + k // 2 - 1] if i + k // 2 - 1 < m else float('inf')
81+
midVal2 = nums2[j + k // 2 - 1] if j + k // 2 - 1 < n else float('inf')
82+
if midVal1 < midVal2:
83+
return findKth(i + k // 2, j, k - k // 2)
84+
return findKth(i, j + k // 2, k - k // 2)
85+
86+
m, n = len(nums1), len(nums2)
87+
left, right = (m + n + 1) // 2, (m + n + 2) // 2
88+
return (findKth(0, 0, left) + findKth(0, 0, right)) / 2
8189
```
8290

8391
### **Java**
8492

8593
```java
86-
94+
class Solution {
95+
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
96+
int m = nums1.length;
97+
int n = nums2.length;
98+
int left = (m + n + 1) / 2;
99+
int right = (m + n + 2) / 2;
100+
return (findKth(nums1, 0, nums2, 0, left) + findKth(nums1, 0, nums2, 0, right)) / 2.0;
101+
}
102+
103+
private int findKth(int[] nums1, int i, int[] nums2, int j, int k) {
104+
if (i >= nums1.length) {
105+
return nums2[j + k - 1];
106+
}
107+
if (j >= nums2.length) {
108+
return nums1[i + k - 1];
109+
}
110+
if (k == 1) {
111+
return Math.min(nums1[i], nums2[j]);
112+
}
113+
int midVal1 = (i + k / 2 - 1 < nums1.length) ? nums1[i + k / 2 - 1] : Integer.MAX_VALUE;
114+
int midVal2 = (j + k / 2 - 1 < nums2.length) ? nums2[j + k / 2 - 1] : Integer.MAX_VALUE;
115+
if (midVal1 < midVal2) {
116+
return findKth(nums1, i + k / 2, nums2, j, k - k / 2);
117+
}
118+
return findKth(nums1, i, nums2, j + k / 2, k - k / 2);
119+
}
120+
}
87121
```
88122

89-
### **Nim**
90-
91-
```nim
92-
proc medianOfTwoSortedArrays(nums1: seq[int], nums2: seq[int]): float =
93-
var
94-
fullList: seq[int] = concat(nums1, nums2)
95-
value: int = fullList.len div 2
96-
97-
fullList.sort()
123+
### **C++**
124+
125+
```cpp
126+
class Solution {
127+
public:
128+
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
129+
int m = nums1.size();
130+
int n = nums2.size();
131+
int left = (m + n + 1) / 2;
132+
int right = (m + n + 2) / 2;
133+
return (findKth(nums1, 0, nums2, 0, left) + findKth(nums1, 0, nums2, 0, right)) / 2.0;
134+
}
135+
136+
int findKth(vector<int>& nums1, int i, vector<int>& nums2, int j, int k) {
137+
if (i >= nums1.size()) return nums2[j + k - 1];
138+
if (j >= nums2.size()) return nums1[i + k - 1];
139+
if (k == 1) return min(nums1[i], nums2[j]);
140+
int midVal1 = i + k / 2 - 1 < nums1.size() ? nums1[i + k / 2 - 1] : INT_MAX;
141+
int midVal2 = j + k / 2 - 1 < nums2.size() ? nums2[j + k / 2 - 1] : INT_MAX;
142+
if (midVal1 < midVal2) return findKth(nums1, i + k / 2, nums2, j, k - k / 2);
143+
return findKth(nums1, i, nums2, j + k / 2, k - k / 2);
144+
}
145+
};
146+
```
98147

99-
if fullList.len mod 2 == 0:
100-
result = (fullList[value - 1] + fullList[value]) / 2
101-
else:
102-
result = fullList[value].toFloat()
148+
### **Go**
149+
150+
```go
151+
func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {
152+
m, n := len(nums1), len(nums2)
153+
left, right := (m+n+1)/2, (m+n+2)/2
154+
var findKth func(i, j, k int) int
155+
findKth = func(i, j, k int) int {
156+
if i >= m {
157+
return nums2[j+k-1]
158+
}
159+
if j >= n {
160+
return nums1[i+k-1]
161+
}
162+
if k == 1 {
163+
return min(nums1[i], nums2[j])
164+
}
165+
midVal1 := math.MaxInt32
166+
midVal2 := math.MaxInt32
167+
if i+k/2-1 < m {
168+
midVal1 = nums1[i+k/2-1]
169+
}
170+
if j+k/2-1 < n {
171+
midVal2 = nums2[j+k/2-1]
172+
}
173+
if midVal1 < midVal2 {
174+
return findKth(i+k/2, j, k-k/2)
175+
}
176+
return findKth(i, j+k/2, k-k/2)
177+
}
178+
return (float64(findKth(0, 0, left)) + float64(findKth(0, 0, right))) / 2.0
179+
}
180+
181+
func min(a, b int) int {
182+
if a < b {
183+
return a
184+
}
185+
return b
186+
}
103187
```
104188

105189
### **...**
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,20 @@
11
class Solution {
22
public:
3-
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
4-
int nums[10000] = { 0 };
5-
int index = 0;
6-
vector<int>::iterator it1 = nums1.begin();
7-
vector<int>::iterator it2 = nums2.begin();
8-
for (; it1 != nums1.end() && it2 != nums2.end();) {
9-
if (*it1 >= *it2) {
10-
nums[index++] = *it2;
11-
it2++;
12-
}
13-
else {
14-
nums[index++] = *it1;
15-
it1++;
16-
}
17-
}
18-
19-
while (it1 != nums1.end()) {
20-
nums[index++] = *it1;
21-
it1++;
22-
}
23-
while (it2 != nums2.end()) {
24-
nums[index++] = *it2;
25-
it2++;
26-
}
3+
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
4+
int m = nums1.size();
5+
int n = nums2.size();
6+
int left = (m + n + 1) / 2;
7+
int right = (m + n + 2) / 2;
8+
return (findKth(nums1, 0, nums2, 0, left) + findKth(nums1, 0, nums2, 0, right)) / 2.0;
9+
}
2710

28-
if (index % 2 == 0) {
29-
return (double)((nums[index/2] + nums[index/2 - 1])/2.0);
30-
}
31-
else {
32-
return (double)(nums[index/2]);
33-
}
34-
35-
}
11+
int findKth(vector<int>& nums1, int i, vector<int>& nums2, int j, int k) {
12+
if (i >= nums1.size()) return nums2[j + k - 1];
13+
if (j >= nums2.size()) return nums1[i + k - 1];
14+
if (k == 1) return min(nums1[i], nums2[j]);
15+
int midVal1 = i + k / 2 - 1 < nums1.size() ? nums1[i + k / 2 - 1] : INT_MAX;
16+
int midVal2 = j + k / 2 - 1 < nums2.size() ? nums2[j + k / 2 - 1] : INT_MAX;
17+
if (midVal1 < midVal2) return findKth(nums1, i + k / 2, nums2, j, k - k / 2);
18+
return findKth(nums1, i, nums2, j + k / 2, k - k / 2);
19+
}
3620
};

0 commit comments

Comments
 (0)