This commit is contained in:
by931
2022-09-06 22:30:37 +08:00
parent 66970f3e38
commit 3d6528675a
796 changed files with 3382 additions and 3382 deletions

View File

@@ -204,7 +204,7 @@ function hide_canvas() {
<p>因此,解决方案上就是,一次循环嵌套查找完成。查找不可使用哈希表,但由于数组有序,时间复杂度是 O(1)。因此整体的时间复杂度就是 O(n)。</p>
<p>我们来看一下具体方案。既然是一次循环,那么就需要一个 for 循环对整个数组进行遍历。每轮遍历的动作是查找 nums[i] 是否已经出现过。因为数组有序,因此只需要去对比 nums[i] 和当前去重数组的最大值是否相等即可。我们用一个 temp 变量保存去重数组的最大值。</p>
<p>如果二者不等,则说明是一个新的数据。我们就需要把这个新数据放到去重数组的最后,并且修改 temp 变量的值,再修改当前去重数组的长度变量 len。直到遍历完就得到了结果。</p>
<p><img src="assets/CgqCHl8O4AaAIRWPAATuBR6nG1c878.gif" alt="1.gif" /></p>
<p><img src="assets/CgqCHl8O4AaAIRWPAATuBR6nG1c878.gif" alt="png" /></p>
<p><strong>最后,我们按照上面的思路进行编码开发,代码如下</strong></p>
<pre><code>public static void main(String[] args) {
int[] nums = {0,0,1,1,1,2,2,3,3,4};
@@ -237,13 +237,13 @@ function hide_canvas() {
<p>回想一下,二分查找适用的重要条件就是,原数组有序。恰好,在这个问题中 nums1 和 nums2 分别都是有序的。而且二分查找的时间复杂度是 O(logn),这和题目中给出的时间复杂度 O(log(m + n)) 的要求也是不谋而合。因此,经过分析,我们可以大胆猜测,此题极有可能要用到二分查找。</p>
<p><strong>我们再来看一下数据结构方面</strong>。如果要用二分查找,就需要用到若干个指针,去约束查找范围。除此以外,并不需要去定义复杂的数据结构。也就是说,空间复杂度是 O(1) 。</p>
<p>好了,接下来,我们就来看一下二分查找如何能解决这个问题。二分查找需要一个分裂点,去把原来的大问题,拆分成两个部分,并在其中一部分继续执行二分查找。既然是查找中位数,我们不妨先试试以中位数作为切分点,看看会产生什么结果。如下图所示:</p>
<p><img src="assets/Ciqc1F8O4BWAJgOUAABMJW6Ihfk508.png" alt="2.png" /></p>
<p><img src="assets/Ciqc1F8O4BWAJgOUAABMJW6Ihfk508.png" alt="png" /></p>
<p>经过切分后,两个数组分别被拆分为 3 个部分,合在一起是 6 个部分。二分查找的思路是,需要从这 6 个部分中,剔除掉一些,让查找的范围缩小。那么,我们来思考一个问题,在这 6 个部分中,目标中位数一定不会发生在哪几个部分呢?</p>
<p><strong>中位数有一个重要的特质,那就是比中位数小的数字个数,和比中位数大的数字个数,是相等的</strong>。围绕这个性质来看,中位数就一定不会发生在 C 和 D 的区间。</p>
<p>如果中位数在 C 部分,那么在 nums1 中,比中位数小的数字就会更多一些。因为 4 &lt; 5nums2 的中位数小于 nums1 的中位数),所以在 nums2 中,比中位数小的数字也会更多一些(最不济也就是一样多)。因此,整体来看,中位数不可能在 C 部分。同理,中位数也不会发生在 D 部分。</p>
<p>接下来,我们就可以在查找范围内,剔除掉 C 部分(永远比中位数大的数字)和 D 部分(永远比中位数小的数字),这样我们就成功地完成了一次二分动作,缩小了查找范围。然而这样并没结束。剔除掉了 C 和 D 之后中位数有可能发生改变。这是因为C 部分的数字个数和 D 部分数字的个数是不相等的。剔除不相等数量的“小数”和“大数”后,会造成中位数的改变。</p>
<p>为了解决这个问题,我们需要对剔除的策略进行修改。一个可行的方法是,如果 C 部分数字更少为 p 个,则剔除 C 部分;并只剔除 D 部分中的 p 个数字。这样就能保证,经过一次二分后,剔除之后的数组的中位数不变。</p>
<p><img src="assets/CgqCHl8O4CKAd3GfAAA88tCPFHQ522.png" alt="3.png" /></p>
<p><img src="assets/CgqCHl8O4CKAd3GfAAA88tCPFHQ522.png" alt="png" /></p>
<p>应该剔除 C 部分和 D 部分。但 D 部分更少,因此剔除 D 和 C 中的 9。</p>
<p>二分查找还需要考虑终止条件。对于这个题目,终止条件必然是某个数组小到无法继续二分的时候。这是因为,每次二分剔除掉的是更少的那个部分。因此,在终止条件中,查找范围应该是一个大数组和一个只有 12 个元素的小数组。这样就需要根据大数组的奇偶性和小数组的数量,拆开 4 个可能性:</p>
<p><strong>可能性一</strong>nums1 奇数个nums2 只有 1 个元素。例如nums1 = [a, b, <strong>c</strong>, d, e]nums2 = [m]。此时,有以下 3 种可能性:</p>
@@ -270,7 +270,7 @@ function hide_canvas() {
<li>如果 n &gt; dm &gt; d则结果为 d。</li>
</ol>
<p>其中46 可以合并为,如果 n &gt; d则返回 m &lt; c ? c : (m &lt; d ? m : d)。</p>
<p><img src="assets/Ciqc1F8Odd-AdDghAAAd2xZYP1g802.png" alt="image" /></p>
<p><img src="assets/Ciqc1F8Odd-AdDghAAAd2xZYP1g802.png" alt="png" /></p>
<p><strong>可能性四</strong>nums1 偶数个nums2 有 2 个元素。例如nums1 = [a, b, <strong>c</strong>, d, e, f]nums2 = [<strong>m</strong>,n]。此时,有以下 6 种可能性:</p>
<ol>
<li>如果 n &lt; b则结果为 b</li>