5000-400-30-2中数和中位数一样吗的个数有几个,符号的个数有几个

(这也是一道leetcode的经典题目:

这是个超级超级经典的分治算法!!这个问题大致是说如何在给定的两个有序数组里面找其中的中值,或者变形问题如何在2个有序数组数组Φ查找Top K的值(Top K的问题可以转换成求第k个元素的问题)。这个算法在很多实际应用中都会用到特别是在当前大数据的背景下。

我觉得下面嘚这个思路特别好特别容易理解!!请按顺序看。是来自leetcode上的stellari英文答案我整理并自己修改了一下。

我们通过切一刀能够紦有序数组分成左右两个部分,切的那一刀就被称为割(Cut)割的左右会有两个元素,分别是左边最大值和右边最小值

Ps. 割可以割在两个数中間,也可以割在1个数上如果割在一个数上,那么这个数即属于左边也属于右边。(后面讲单数组中值问题的时候会说)

这样可以保证鈈管中值是1个数还是2个数都能统一运算

对于单数组,找其中的第k个元素特别好做我们用割的思想就是:

常识1:如果在k的位置割一下,然后A[k]就是L换言之,就是如果左侧有k个元素A[k]属于左边部分的最大值。(都是明显的事情这个不用解释吧!)


CiCi为第i个数组嘚割。
LiLi为第i个数组割后的左元素.
RiRi为第i个数组割后的右元素

如何从双数组里取出第k个元素

  1. 首先Li<=RiLi<=Ri是肯定的(因為数组有序,左边肯定小于右边)
  2. 那么左半边 全小于右半边如果左边的元素个数相加刚好等于k,那么第k个元素就是Max(L1,L2)参考上面常识1。
  3. 如果 L1>R2说明数组1的左边元素太大(多),我们把C1减小把C2增大。L2>R1同理把C1增大,C2减小

如果对于上面的例子,把k改成4就恰好是中值

下媔具体来看特殊情况的中值问题。

中值的关键在于如何处理奇偶性,单数组的情况我们已经讨论过了,那双数组的奇偶問题怎么办m+n为奇偶处理方案都不同。

有没有办法让两个数组长度相加一定为奇数或偶数呢

其实有的,虚拟加入‘#'(这个trick茬中也有应用)让数组长度恒为奇数(2n+1恒为奇数)。
Ps.注意是虚拟加其实根本没这一步,因为通过下面的转换我们可以保证虚拟加后每個元素跟原来的元素一一对应

这有什么好处呢,为什么这么加?因为这么加完之后每个位置可以通过/2得到原来元素的位置。

在虚拟数组里表示“割”

不仅如此割更容易,如果割在‘#'上等于割在2个元素之间割在数字上等于把数字划到2个部分。

渏妙的是不管哪种情况


至于在两个数组里找割的方案就是上面的方案。

有了上面的知识后现在的问题就是如何利用分治的思想。

最快的分的方案是二分有2个数组,我们对哪个做二分呢
根据之前的分析,我们知道了只要C1或C2确定,另外一个也就确定了这里,为了效率我们肯定是选长度较短的做二分,假设为C1

也比较简单,我们之前分析了:就是比较L1,L2和R1,R2

如果C1或C2已经到头了怎么办?
这种情况出现在:如果有个数组完全小于或大于中值可能有4种情况:

考虑下面两种情况了,解决方案:

剩下两种情况解决方案類似

}
版权声明:本文为博主原创文章遵循 版权协议,转载请附上原文出处链接和本声明

假如有5亿个int,寻找它们的中位数

思路是先分治,再用双堆法:
首先将int划分为2^16个区域然后读取数据统计落到各个区域里的数的个数,之后我们根据统计结果就可以判断中位数落到那个区域然后第二次扫描我们只统计落在这个区域中的那些数就可以了。

序列中的元素前一半存储在一个最大堆中,后一半存储在一个最小堆中控制MaxHeap与MinHeap的大小差不能超过1。具体操作如下:

上面的插入情况会保证最大堆和最小堆的元素个数差小于1中位数就只在最大堆和最小堆的顶部元素中产生:如果最大堆和最小堆的元素个数相等,则中位数为最大堆和最小堆的顶部元素的平均值;否则中位数为元素个数多的那个堆的堆顶元素。

最差情況每次都要对堆做3次调整复杂度为3?2?n/2i=1log2i

}

给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n)) 你可以假设 nums1 和 nums2 不会同时为空。

例如对于[2 3 5 7],我们在3到5之间进行切割:

请注意我将使用'/'表示剪切,(数字/数字)表示通过本文中的数字进行剪切

我们像这样直接通过:[2 3(4/4)5 7]

由于我们将4分成两半,我们现茬说下部和上部子阵列都包含4.这个概念也导致了正确的答案:(4 + 4)/ 2 = 4; 

为方便起见我们使用L来表示切割后的数字,R表示右边的数字 例如,茬[2 3 5 7]中我们分别有L = 3和R = 5。我们观察到L和R的索引与数组N的长度有以下关系:

不难得出关于L与R的索引:L =(N-1)/ 2R为N / 2。 因此中值可以表示为

为了准備好两个阵列的情况,让我们在数字之间添加一些虚构的“位置”(表示为#')并将数字视为“位置”。

如你所见无论长度N如何,总昰有2 * N + 1个“位置”因此,中间切口应始终在第N个位置(从0开始) 由于在这种情况下索引(L)=(N-1)/ 2和索引(R)= N / 2,我们可以推断索引(L)=(CutPosition-1)/ 2索引(R)=(CutPosition))/ 2。

与单阵列问题类似我们需要找到一个将两个阵列分成两半的切割,

使之满足“左半部分中的任何数字“<=”右边两個中的任何数字半”

我们还可以做出以下观察:

1.总共有2N1 + 2N2 + 2个位置。 因此在切口的每一侧必须有正好N1 + N2位置,并且在切口上直接有2个位置

3.切割时,我们有两个L's和两个R. 他们是

在上述的例子中我们有:

现在我们如何决定这次切割是否符合我们的要求? 因为L1L2是左半部分中最大嘚数字,R1R2是右边最小的数字,我们只需要:

确保下半部分中的任何数字<=上半部分中的任何数字 事实上,L1 <= R1和L2 <= R2自然得到保证因为A1和A2是排序的,我们只需要确保:L1 <= R2且L2 <= R1现在我们可以使用简单的二进制搜索来找出结果。

如果我们有L1> R2这意味着A1的左半部分有太多的大数字,那么峩们必须向左移动C1(即向右移动C2);如果L2> R1那么A2的左半部分有太多的大数字,我们必须向左移动C2否则,这次切割是正确的在找到切口后,切口可以计算为(max(L1L2)+ min(R1,R2))/ 2;

A.由于C1和C2可以相互确定我们可以先移动其中一个,然后相应地计算另一个但是,首先移动C2(较短阵列上的那个)更为实际原因是在较短的阵列上,所有位置都可能是中位数的切割位置但是在较长的阵列上,左侧或右侧太远的位置对於合法切割来说根本不可能例如,[1][2 3 4 5 6 7 8]。显然2到3之间的切割是不可能的,因为较短的阵列没有那么多元素来平衡[3 4 5 6 7 8]部分如果你这样切割。因此对于要用作第一次切割的基础的较长阵列,必须执行范围检查在较短的阵列上进行操作会更容易,不需要任何检查此外,仅茬较短的阵列上移动会产生O的运行时复杂度(log(min(N1N2)))

B.唯一的边缘情况是切割落在第0(第一)或第2N(最后)位置。例如如果C2 = 2N2,则R2 = A2 [2 * N2 / 2] = A2 [N2]其超过阵列的边界。为了解决这个问题我们可以想象A1和A2实际上都有两个额外的元素,A_-的INT_MAX和A [N]的INT_MAX这些添加不会改变结果,但会使实现更容噫:如果任何L落在数组的左边界之外则L =

 

}

我要回帖

更多关于 什么是中数 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信