|
68 | 68 |
|
69 | 69 | <!-- 这里可写通用的实现逻辑 -->
|
70 | 70 |
|
| 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 | +
|
71 | 83 | <!-- tabs:start -->
|
72 | 84 |
|
73 | 85 | ### **Python3**
|
|
77 | 89 | ```python
|
78 | 90 | class Solution:
|
79 | 91 | 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 |
90 | 108 | ```
|
91 | 109 |
|
92 | 110 | ### **Java**
|
93 | 111 |
|
94 | 112 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
95 | 113 |
|
96 | 114 | ```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 | +} |
98 | 142 | ```
|
99 | 143 |
|
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 | +``` |
109 | 168 |
|
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 | +} |
114 | 208 | ```
|
115 | 209 |
|
116 | 210 | ### **...**
|
|
0 commit comments