49
49
50
50
** 方法一:分治**
51
51
52
- 本题限制了时间复杂度为 $O(\log (m+ n))$,看到这个时间复杂度,自然而然的想到了应该使用二分查找法来求解。那么回顾一下中位数的定义,如果某个有序数组长度是奇数,那么其中位数就是最中间那个,如果是偶数,那么就是最中间两个数字的平均值。这里对于两个有序数组也是一样的,假设两个有序数组的长度分别为 $m$ 和 $n$,由于两个数组长度之和 $m+n$ 的奇偶不确定,因此需要分情况来讨论,对于奇数的情况,直接找到最中间的数即可,偶数的话需要求最中间两个数的平均值。为了简化代码,不分情况讨论,我们使用一个小 trick,我们分别找第 $\frac{m+n+1}{2}$ 和 $\frac{m+n+2}{2}$ 个,然后求其平均值即可,这对奇偶数均适用。假如 $m+n$ 为奇数的话,那么其实 $\frac{m+n+1}{2}$ 和 $\frac{m+n+2}{2}$ 的值相等,相当于两个相同的数字相加再除以 2,还是其本身 。
52
+ 题目要求算法的时间复杂度为 $O(\log (m + n))$,因此不能直接遍历两个数组,而是需要使用二分查找的方法 。
53
53
54
- 这里我们需要定义一个函数来在两个有序数组中找到第 $k$ 个元素,下面重点来看如何实现找到第 $k$ 个元素 。
54
+ 如果 $m + n$ 是奇数,那么中位数就是第 $\left\lfloor\frac{m + n + 1}{2}\right\rfloor$ 个数;如果 $m + n$ 是偶数,那么中位数就是第 $\left\lfloor\frac{m + n + 1}{2}\right\rfloor$ 和第 $\left\lfloor\frac{m + n + 2}{2}\right\rfloor$ 个数的平均数。实际上,我们可以统一为求第 $\left\lfloor\frac{m + n + 1}{2}\right\rfloor$ 个数和第 $\left\lfloor\frac{m + n + 2}{2}\right\rfloor$ 个数的平均数 。
55
55
56
- 首先,为了避免产生新的数组从而增加时间复杂度,我们使用两个变量 $i$ 和 $j$ 分别来标记数组 ` nums1 ` 和 ` nums2 ` 的起始位置。然后来处理一些边界问题,比如当某一个数组的起始位置大于等于其数组长度时,说明其所有数字均已经被淘汰了,相当于一个空数组了,那么实际上就变成了在另一个数组中找数字,直接就可以找出来了。还有就是如果 $k=1$ 的话,那么我们只要比较 ` nums1 ` 和 ` nums2 ` 的起始位置 $i$ 和 $j$ 上的数字就可以了 。
56
+ 因此,我们可以设计一个函数 $f(i, j, k)$,表示在数组 $nums1$ 的区间 $ [ i, m)$ 和数组 $ nums2$ 的区间 $ [ j, n)$ 中,求第 $k$ 小的数。那么中位数就是 $f(0, 0, \left\lfloor\frac{m + n + 1}{2}\right\rfloor)$ 和 $f(0, 0, \left\lfloor\frac{m + n + 2}{2}\right\rfloor)$ 的平均数 。
57
57
58
- 难点就在于一般的情况怎么处理?因为我们需要在两个有序数组中找到第 $k$ 个元素,为了加快搜索的速度,我们要使用二分法,对 $k$ 二分,意思是我们需要分别在 `nums1` 和 `nums2` 中查找第 $\left \lfloor \frac{k}{2} \right \rfloor$ 个元素,注意这里由于两个数组的长度不定,所以有可能某个数组没有第 $\left \lfloor \frac{k}{2} \right \rfloor$ 个数字,所以我们需要先检查一下,数组中到底存不存在第 $\left \lfloor \frac{k}{2} \right \rfloor$ 个数字,如果存在就取出来,否则就赋值上一个整型最大值。如果某个数组没有第 $\left \lfloor \frac{k}{2} \right \rfloor$ 个数字,那么我们就淘汰另一个数字的前 $\left \lfloor \frac{k}{2} \right \rfloor$ 个数字即可。有没有可能两个数组都不存在第 $\left \lfloor \frac{k}{2} \right \rfloor$ 个数字呢,这道题里是不可能的,因为我们的 $k$ 不是任意给的,而是给的 $m+n$ 的中间值,所以必定至少会有一个数组是存在第 $\left \lfloor \frac{k}{2} \right \rfloor$ 个数字的。
58
+ 函数 $f(i, j, k)$ 的实现思路如下:
59
59
60
- 最后是二分法的核心,比较这两个数组的第 $\left \lfloor \frac{k}{2} \right \rfloor$ 小的数字 ` midVal1 ` 和 ` midVal2 ` 的大小,如果第一个数组的第 $\left \lfloor \frac{k}{2} \right \rfloor$ 个数字小的话,那么说明我们要找的数字肯定不在 ` nums1 ` 中的前 $\left \lfloor \frac{k}{2} \right \rfloor$ 个数字,所以我们可以将其淘汰,将 ` nums1 ` 的起始位置向后移动 $\left \lfloor \frac{k}{2} \right \rfloor$ 个,并且此时的 $k$ 也自减去 $\left \lfloor \frac{k}{2} \right \rfloor$,调用递归。反之,我们淘汰 ` nums2 ` 中的前 $\left \lfloor \frac{k}{2} \right \rfloor$ 个数字,并将 ` nums2 ` 的起始位置向后移动 $\left \lfloor \frac{k}{2} \right \rfloor$ 个,并且此时的 $k$ 也自减去 $\left \lfloor \frac{k}{2} \right \rfloor$,调用递归即可。
60
+ - 如果 $i \geq m$,说明数组 $nums1$ 的区间 $[ i, m)$ 为空,因此直接返回 $nums2[ j + k - 1] $;
61
+ - 如果 $j \geq n$,说明数组 $nums2$ 的区间 $[ j, n)$ 为空,因此直接返回 $nums1[ i + k - 1] $;
62
+ - 如果 $k = 1$,说明要找第一个数,因此只需要返回 $nums1[ i] $ 和 $nums2[ j] $ 中的最小值;
63
+ - 否则,我们分别在两个数组中查找第 $\left\lfloor\frac{k}{2}\right\rfloor$ 个数,设为 $x$ 和 $y$。(注意,如果某个数组不存在第 $\left\lfloor\frac{k}{2}\right\rfloor$ 个数,那么我们将第 $\left\lfloor\frac{k}{2}\right\rfloor$ 个数视为 $+\infty$。)比较 $x$ 和 $y$ 的大小:
64
+ - 如果 $x \leq y$,则说明数组 $nums1$ 的第 $\left\lfloor\frac{k}{2}\right\rfloor$ 个数不可能是第 $k$ 小的数,因此我们可以排除数组 $nums1$ 的区间 $[ i, i + \left\lfloor\frac{k}{2}\right\rfloor)$,递归调用 $f(i + \left\lfloor\frac{k}{2}\right\rfloor, j, k - \left\lfloor\frac{k}{2}\right\rfloor)$。
65
+ - 如果 $x > y$,则说明数组 $nums2$ 的第 $\left\lfloor\frac{k}{2}\right\rfloor$ 个数不可能是第 $k$ 小的数,因此我们可以排除数组 $nums2$ 的区间 $[ j, j + \left\lfloor\frac{k}{2}\right\rfloor)$,递归调用 $f(i, j + \left\lfloor\frac{k}{2}\right\rfloor, k - \left\lfloor\frac{k}{2}\right\rfloor)$。
61
66
62
- > 实际是比较两个数组中的第 $\left \lfloor \frac{k}{2} \right \rfloor$ 个数字哪一个可能到达最后合并后排序数组中的第 $k$ 个元素的位置,其中小的那个数字注定不可能到达,所以可以直接将小的元素对应的数组的前 $\left \lfloor \frac{k}{2} \right \rfloor$ 个数字淘汰。
63
-
64
- 时间复杂度 $O(\log (m+n))$,其中 $m$ 和 $n$ 是两个数组的长度。
67
+ 时间复杂度 $O(\log(m + n))$,空间复杂度 $O(\log(m + n))$。其中 $m$ 和 $n$ 分别是数组 $nums1$ 和 $nums2$ 的长度。
65
68
66
69
<!-- tabs:start -->
67
70
72
75
``` python
73
76
class Solution :
74
77
def findMedianSortedArrays (self , nums1 : List[int ], nums2 : List[int ]) -> float :
75
- def findKth ( i , j , k ) :
78
+ def f ( i : int , j : int , k : int ) -> int :
76
79
if i >= m:
77
80
return nums2[j + k - 1 ]
78
81
if j >= n:
79
82
return nums1[i + k - 1 ]
80
83
if k == 1 :
81
84
return min (nums1[i], nums2[j])
82
- midVal1 = nums1[i + k // 2 - 1 ] if i + k // 2 - 1 < m else inf
83
- midVal2 = nums2[j + k // 2 - 1 ] if j + k // 2 - 1 < n else inf
84
- if midVal1 < midVal2:
85
- return findKth(i + k // 2 , j, k - k // 2 )
86
- return findKth(i, j + k // 2 , k - k // 2 )
85
+ p = k // 2
86
+ x = nums1[i + p - 1 ] if i + p - 1 < m else inf
87
+ y = nums2[j + p - 1 ] if j + p - 1 < n else inf
88
+ return f(i + p, j, k - p) if x < y else f(i, j + p, k - p)
87
89
88
90
m, n = len (nums1), len (nums2)
89
- left, right = (m + n + 1 ) // 2 , (m + n + 2 ) // 2
90
- return (findKth(0 , 0 , left) + findKth(0 , 0 , right)) / 2
91
+ a = f(0 , 0 , (m + n + 1 ) // 2 )
92
+ b = f(0 , 0 , (m + n + 2 ) // 2 )
93
+ return (a + b) / 2
91
94
```
92
95
93
96
### ** Java**
@@ -96,30 +99,35 @@ class Solution:
96
99
97
100
``` java
98
101
class Solution {
102
+ private int m;
103
+ private int n;
104
+ private int [] nums1;
105
+ private int [] nums2;
106
+
99
107
public double findMedianSortedArrays (int [] nums1 , int [] nums2 ) {
100
- int m = nums1. length;
101
- int n = nums2. length;
102
- int left = (m + n + 1 ) / 2 ;
103
- int right = (m + n + 2 ) / 2 ;
104
- return (findKth(nums1, 0 , nums2, 0 , left) + findKth(nums1, 0 , nums2, 0 , right)) / 2.0 ;
108
+ m = nums1. length;
109
+ n = nums2. length;
110
+ this . nums1 = nums1;
111
+ this . nums2 = nums2;
112
+ int a = f(0 , 0 , (m + n + 1 ) / 2 );
113
+ int b = f(0 , 0 , (m + n + 2 ) / 2 );
114
+ return (a + b) / 2.0 ;
105
115
}
106
116
107
- private int findKth (int [] nums1 , int i , int [] nums2 , int j , int k ) {
108
- if (i >= nums1 . length ) {
117
+ private int f (int i , int j , int k ) {
118
+ if (i >= m ) {
109
119
return nums2[j + k - 1 ];
110
120
}
111
- if (j >= nums2 . length ) {
121
+ if (j >= n ) {
112
122
return nums1[i + k - 1 ];
113
123
}
114
124
if (k == 1 ) {
115
125
return Math . min(nums1[i], nums2[j]);
116
126
}
117
- int midVal1 = (i + k / 2 - 1 < nums1. length) ? nums1[i + k / 2 - 1 ] : Integer . MAX_VALUE ;
118
- int midVal2 = (j + k / 2 - 1 < nums2. length) ? nums2[j + k / 2 - 1 ] : Integer . MAX_VALUE ;
119
- if (midVal1 < midVal2) {
120
- return findKth(nums1, i + k / 2 , nums2, j, k - k / 2 );
121
- }
122
- return findKth(nums1, i, nums2, j + k / 2 , k - k / 2 );
127
+ int p = k / 2 ;
128
+ int x = i + p - 1 < m ? nums1[i + p - 1 ] : 1 << 30 ;
129
+ int y = j + p - 1 < n ? nums2[j + p - 1 ] : 1 << 30 ;
130
+ return x < y ? f(i + p, j, k - p) : f(i, j + p, k - p);
123
131
}
124
132
}
125
133
```
@@ -130,21 +138,25 @@ class Solution {
130
138
class Solution {
131
139
public:
132
140
double findMedianSortedArrays(vector<int >& nums1, vector<int >& nums2) {
133
- int m = nums1.size();
134
- int n = nums2.size();
135
- int left = (m + n + 1) / 2;
136
- int right = (m + n + 2) / 2;
137
- return (findKth(nums1, 0, nums2, 0, left) + findKth(nums1, 0, nums2, 0, right)) / 2.0;
138
- }
139
-
140
- int findKth(vector<int>& nums1, int i, vector<int>& nums2, int j, int k) {
141
- if (i >= nums1.size()) return nums2[j + k - 1];
142
- if (j >= nums2.size()) return nums1[i + k - 1];
143
- if (k == 1) return min(nums1[i], nums2[j]);
144
- int midVal1 = i + k / 2 - 1 < nums1.size() ? nums1[i + k / 2 - 1] : INT_MAX;
145
- int midVal2 = j + k / 2 - 1 < nums2.size() ? nums2[j + k / 2 - 1] : INT_MAX;
146
- if (midVal1 < midVal2) return findKth(nums1, i + k / 2, nums2, j, k - k / 2);
147
- return findKth(nums1, i, nums2, j + k / 2, k - k / 2);
141
+ int m = nums1.size(), n = nums2.size();
142
+ function<int(int, int, int)> f = [ &] (int i, int j, int k) {
143
+ if (i >= m) {
144
+ return nums2[ j + k - 1] ;
145
+ }
146
+ if (j >= n) {
147
+ return nums1[ i + k - 1] ;
148
+ }
149
+ if (k == 1) {
150
+ return min(nums1[ i] , nums2[ j] );
151
+ }
152
+ int p = k / 2;
153
+ int x = i + p - 1 < m ? nums1[ i + p - 1] : 1 << 30;
154
+ int y = j + p - 1 < n ? nums2[ j + p - 1] : 1 << 30;
155
+ return x < y ? f(i + p, j, k - p) : f(i, j + p, k - p);
156
+ };
157
+ int a = f(0, 0, (m + n + 1) / 2);
158
+ int b = f(0, 0, (m + n + 2) / 2);
159
+ return (a + b) / 2.0;
148
160
}
149
161
};
150
162
```
@@ -154,9 +166,8 @@ public:
154
166
```go
155
167
func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {
156
168
m, n := len(nums1), len(nums2)
157
- left , right := (m+n+1 )/2 , (m+n+2 )/2
158
- var findKth func (i, j, k int ) int
159
- findKth = func (i, j, k int ) int {
169
+ var f func(i, j, k int) int
170
+ f = func(i, j, k int) int {
160
171
if i >= m {
161
172
return nums2[j+k-1]
162
173
}
@@ -166,20 +177,21 @@ func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {
166
177
if k == 1 {
167
178
return min(nums1[i], nums2[j])
168
179
}
169
- midVal1 := math. MaxInt32
170
- midVal2 := math. MaxInt32
171
- if i+k/ 2 - 1 < m {
172
- midVal1 = nums1[i+k/ 2 - 1 ]
180
+ p := k / 2
181
+ x, y := 1<<30, 1<<30
182
+ if ni := i + p - 1; ni < m {
183
+ x = nums1[ni ]
173
184
}
174
- if j+k/ 2 - 1 < n {
175
- midVal2 = nums2[j+k/ 2 - 1 ]
185
+ if nj := j + p - 1; nj < n {
186
+ y = nums2[nj ]
176
187
}
177
- if midVal1 < midVal2 {
178
- return findKth (i+k/ 2 , j, k-k/ 2 )
188
+ if x < y {
189
+ return f (i+p , j, k-p )
179
190
}
180
- return findKth (i, j+k/ 2 , k-k/ 2 )
191
+ return f (i, j+p , k-p )
181
192
}
182
- return (float64 (findKth (0 , 0 , left)) + float64 (findKth (0 , 0 , right))) / 2.0
193
+ a, b := f(0, 0, (m+n+1)/2), f(0, 0, (m+n+2)/2)
194
+ return float64(a+b) / 2.0
183
195
}
184
196
185
197
func min(a, b int) int {
@@ -190,6 +202,102 @@ func min(a, b int) int {
190
202
}
191
203
```
192
204
205
+ ### ** TypeScript**
206
+
207
+ ``` ts
208
+ function findMedianSortedArrays(nums1 : number [], nums2 : number []): number {
209
+ const m = nums1 .length ;
210
+ const n = nums2 .length ;
211
+ const f = (i : number , j : number , k : number ): number => {
212
+ if (i >= m ) {
213
+ return nums2 [j + k - 1 ];
214
+ }
215
+ if (j >= n ) {
216
+ return nums1 [i + k - 1 ];
217
+ }
218
+ if (k == 1 ) {
219
+ return Math .min (nums1 [i ], nums2 [j ]);
220
+ }
221
+ const p = Math .floor (k / 2 );
222
+ const x = i + p - 1 < m ? nums1 [i + p - 1 ] : 1 << 30 ;
223
+ const y = j + p - 1 < n ? nums2 [j + p - 1 ] : 1 << 30 ;
224
+ return x < y ? f (i + p , j , k - p ) : f (i , j + p , k - p );
225
+ };
226
+ const a = f (0 , 0 , Math .floor ((m + n + 1 ) / 2 ));
227
+ const b = f (0 , 0 , Math .floor ((m + n + 2 ) / 2 ));
228
+ return (a + b ) / 2 ;
229
+ }
230
+ ```
231
+
232
+ ### ** JavaScript**
233
+
234
+ ``` js
235
+ /**
236
+ * @param {number[]} nums1
237
+ * @param {number[]} nums2
238
+ * @return {number}
239
+ */
240
+ var findMedianSortedArrays = function (nums1 , nums2 ) {
241
+ const m = nums1 .length ;
242
+ const n = nums2 .length ;
243
+ const f = (i , j , k ) => {
244
+ if (i >= m) {
245
+ return nums2[j + k - 1 ];
246
+ }
247
+ if (j >= n) {
248
+ return nums1[i + k - 1 ];
249
+ }
250
+ if (k == 1 ) {
251
+ return Math .min (nums1[i], nums2[j]);
252
+ }
253
+ const p = Math .floor (k / 2 );
254
+ const x = i + p - 1 < m ? nums1[i + p - 1 ] : 1 << 30 ;
255
+ const y = j + p - 1 < n ? nums2[j + p - 1 ] : 1 << 30 ;
256
+ return x < y ? f (i + p, j, k - p) : f (i, j + p, k - p);
257
+ };
258
+ const a = f (0 , 0 , Math .floor ((m + n + 1 ) / 2 ));
259
+ const b = f (0 , 0 , Math .floor ((m + n + 2 ) / 2 ));
260
+ return (a + b) / 2 ;
261
+ };
262
+ ```
263
+
264
+ ### ** TypeScript**
265
+
266
+ ``` ts
267
+ public class Solution {
268
+ private int m;
269
+ private int n;
270
+ private int [] nums1;
271
+ private int [] nums2;
272
+
273
+ public double FindMedianSortedArrays(int [] nums1 , int [] nums2 ) {
274
+ m = nums1 .Length ;
275
+ n = nums2 .Length ;
276
+ this .nums1 = nums1 ;
277
+ this .nums2 = nums2 ;
278
+ int a = f (0 , 0 , (m + n + 1 ) / 2 );
279
+ int b = f (0 , 0 , (m + n + 2 ) / 2 );
280
+ return (a + b ) / 2.0 ;
281
+ }
282
+
283
+ private int f(int i , int j , int k ) {
284
+ if (i >= m ) {
285
+ return nums2 [j + k - 1 ];
286
+ }
287
+ if (j >= n ) {
288
+ return nums1 [i + k - 1 ];
289
+ }
290
+ if (k == 1 ) {
291
+ return Math .Min (nums1 [i ], nums2 [j ]);
292
+ }
293
+ int p = k / 2 ;
294
+ int x = i + p - 1 < m ? nums1 [i + p - 1 ] : 1 << 30 ;
295
+ int y = j + p - 1 < n ? nums2 [j + p - 1 ] : 1 << 30 ;
296
+ return x < y ? f (i + p , j , k - p ) : f (i , j + p , k - p );
297
+ }
298
+ }
299
+ ```
300
+
193
301
### ** ...**
194
302
195
303
```
0 commit comments