Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/cmake/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 求未排序数组的中值_Algorithm_Heap_Median - Fatal编程技术网

Algorithm 求未排序数组的中值

Algorithm 求未排序数组的中值,algorithm,heap,median,Algorithm,Heap,Median,为了找到未排序数组的中位数,我们可以在O(nlogn)时间内为n个元素创建一个最小堆,然后我们可以逐个提取n/2个元素以获得中位数。但这种方法需要O(nlogn)时间 我们能在O(n)时间内用某种方法做同样的事情吗?如果可以,请告诉或建议一些方法。您可以使用该算法在线性时间内查找未排序数组的中值。在O(n)中有效,这也用于快速排序的分区步骤。可以在O(n)中使用快速选择算法,请参考k阶统计量(随机算法) 快速选择算法可以在线性(O(n))运行时找到数组的第k个最小元素。下面是python的一个实

为了找到未排序数组的中位数,我们可以在O(nlogn)时间内为n个元素创建一个最小堆,然后我们可以逐个提取n/2个元素以获得中位数。但这种方法需要O(nlogn)时间


我们能在O(n)时间内用某种方法做同样的事情吗?如果可以,请告诉或建议一些方法。

您可以使用该算法在线性时间内查找未排序数组的中值。

在O(n)中有效,这也用于快速排序的分区步骤。

可以在O(n)中使用快速选择算法,请参考k阶统计量(随机算法)

快速选择算法可以在线性(
O(n)
)运行时找到数组的第k个最小元素。下面是python的一个实现:

随机导入
def分区(L,v):
较小的=[]
更大=[]
对于L中的val:
如果valv:biger+=[val]
返回值(较小[v],较大)
def top_k(左、右):
v=L[random.randrange(len(L))]
(左、中、右)=分区(L、v)
#为了清楚起见,在下面使用中间部分(代替[v])
如果len(左)==k:返回左
如果len(左)+1==k:返回左+中
如果len(左)>k:返回top_k(左,k)
返回左+中+上(右,k-镜头(左)-镜头(中))
def中值(L):
n=len(L)
l=顶部(l,n/2+1)
返回最大值(l)

正如维基百科所说,中位数理论上为o(N),但实际上并未使用,因为寻找“好”支点的开销使其速度太慢。

以下是用于在数组中查找第k个元素的Quickselect算法的Java源代码:

/**
 * Returns position of k'th largest element of sub-list.
 * 
 * @param list list to search, whose sub-list may be shuffled before
 *            returning
 * @param lo first element of sub-list in list
 * @param hi just after last element of sub-list in list
 * @param k
 * @return position of k'th largest element of (possibly shuffled) sub-list.
 */
static int select(double[] list, int lo, int hi, int k) {
    int n = hi - lo;
    if (n < 2)
        return lo;

    double pivot = list[lo + (k * 7919) % n]; // Pick a random pivot

    // Triage list to [<pivot][=pivot][>pivot]
    int nLess = 0, nSame = 0, nMore = 0;
    int lo3 = lo;
    int hi3 = hi;
    while (lo3 < hi3) {
        double e = list[lo3];
        int cmp = compare(e, pivot);
        if (cmp < 0) {
            nLess++;
            lo3++;
        } else if (cmp > 0) {
            swap(list, lo3, --hi3);
            if (nSame > 0)
                swap(list, hi3, hi3 + nSame);
            nMore++;
        } else {
            nSame++;
            swap(list, lo3, --hi3);
        }
    }
    assert (nSame > 0);
    assert (nLess + nSame + nMore == n);
    assert (list[lo + nLess] == pivot);
    assert (list[hi - nMore - 1] == pivot);
    if (k >= n - nMore)
        return select(list, hi - nMore, hi, k - nLess - nSame);
    else if (k < nLess)
        return select(list, lo, lo + nLess, k);
    return lo + k;
}
/**
*返回子列表第k个最大元素的位置。
* 
*@param list要搜索的列表,其子列表可能会在
*返回
*@param lo列表中子列表的第一个元素
*@param hi位于列表中子列表的最后一个元素之后
*@param k
*@返回子列表中第k个最大元素的位置(可能被洗牌)。
*/
静态整数选择(双[]列表,整数低,整数高,整数k){
int n=高-低;
if(n<2)
返回lo;
双支点=列表[lo+(k*7919)%n];//选择一个随机支点
//分类列表到[透视]
int nLess=0,nSame=0,nMore=0;
int-lo3=lo;
int-hi3=hi;
而(lo30){
交换(列表,lo3,--hi3);
如果(nSame>0)
交换(列表、hi3、hi3+nSame);
nMore++;
}否则{
nSame++;
交换(列表,lo3,--hi3);
}
}
断言(nSame>0);
断言(nLess+nSame+nMore==n);
断言(列表[lo+nLess]==pivot);
断言(列表[hi-nMore-1]==pivot);
如果(k>=n-nMore)
返回select(list,hi-nMore,hi,k-nLess-nSame);
else if(k
我没有包括compare和swap方法的源代码,因此很容易将代码更改为使用Object[],而不是double[]


实际上,您可以预期上述代码为o(N)。

我已经对@dasblinkenlight答案进行了投票,因为中值算法实际上在o(N)时间内解决了这个问题。我只想补充一点,这个问题也可以通过使用堆在O(n)时间内解决。通过使用自底向上的方法,可以在O(n)时间内完成堆的构建。请参阅下面的文章以获得详细的解释

假设数组有N个元素,则必须构建两个堆:一个包含前N/2个元素的MaxHeap(如果N为奇数,则为(N/2)+1)和一个包含其余元素的MinHeap。如果N是奇数,则中值是MaxHeap(O(1)的最大元素,通过获取最大值)。如果N是偶数,那么中间值是(MaxHeap.max()+MinHeap.min())/2这也需要O(1)。因此,整个操作的实际成本是堆构建操作,即O(n)


顺便说一句,当您事先不知道数组元素的数目时(例如,如果您必须为一个整数流解决相同的问题),这种MaxHeap/MinHeap算法也可以工作。您可以在下面的文章中看到有关如何解决此问题的更多详细信息。答案是“不,在线性时间内无法找到任意未排序数据集的中值”。一般来说(据我所知),最好的方法是中位数(以获得一个良好的开端),然后是Quickselect。Ref:[

问题是:在未排序的数组中查找第k个最大的元素

将数组分成n/5组,每组由5个元素组成

现在a1,a2,a3…a(n/5)代表每组的中位数

x=元素a1、a2、…a(n/5)的中值

现在,如果kn/2,那么我们可以移除中位数小于x的组中最小的、第二小的和第三小的元素。我们现在可以用7n/10元素再次调用函数,并找到第(k-3n/10)个最大值

时间复杂性分析: T(n)在大小为n的数组中查找第k个最大值的时间复杂度

T(n)=T(n/5)+T(7n/10)+O(n)

如果你解这个,你会发现T(n)实际上是O(n)


n/5+7n/10=9n/10给定大小分别为mn的两个排序数组nums1nums2,返回两个排序数组的中值

例1:

Input: nums1 = [1,3], nums2 = [2]
Output: 2.00000
Explanation: merged array = [1,2,3] and median is 2.
代码:


请记住,如果需要O(nlogn),那么您最好对数组进行排序并将索引除以2。构建堆需要O(n)时间而不是O(nlogn)@JerryGoyal,如果您同时拥有所有元素,那么构建堆需要O(n)。但是如果您拥有元素流,则需要O(nlogn).这就像一次推一个元素
class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        merged_array = sorted(nums1 + nums2)
        if len(merged_array) % 2 == 0:
            index = int(len(merged_array)/2)
            output =  (merged_array[index - 1] +  merged_array[index])/2
        else: 
            index = int(len(merged_array)/2)
            output = merged_array[index]
        return output