我希望重复重新排列数组或std::vector
,以便最小值是第一个元素,最大值是最后一个元素,arr[(0+lastIdx)/2]
是中位数,中位数之前的元素小于中位数,中位数之后的元素会更大。在每次查询min,max和median之后,我将对数据进行更改,并且我想再次快速查询这三个值。
每次我想重新排列数组时,数组都是一个大小相同的数组。
使用std::nth_element
我可以在正确的位置获得中位数,然后我可以迭代数组以获得最小值和最大值。对于单个阵列,这实现了O(n)复杂度,并且显然这无法改进。 (也许,O(n)前面的复杂性常数)
我需要对数组进行操作,首先,我重新排列数组,然后执行其他操作,这会使排列的数组再次完全解除排列,但不会插入新值。然后,我一遍又一遍地重复这个过程。
答案 0 :(得分:0)
即使你以某种方式设法降低了将最小值,最大值,中位数定位为零的成本,
您仍然需要将错位元素放在中位数的下方或上方。这意味着每次n/2 - 1 permutations
的最坏情况。
O(n)
时间,O(1)
空格)O(n)
时间,O(1)
空间)O(n)
时间,O(1)
空间)的第三次传递,median of median algorithm及其位置0
,一个用于上面的n-1
。虽然当前below
元素应该是它的位置,但是增加该索引。当前above
元素应该是它的位置,减少该索引。当找到错位的元素时,在下方和上方交换。只要below < above
重复一遍。 (O(n)
时间,O(1)
空间)步骤4,5的逻辑:当它们应该在上面时,低于中位数的元素的数量正好是上面的元素的数量,应该在下面。
当然你可以在一个函数中合并传递1,2,3,但这不会影响复杂性
让我们运行:
{3, 7, 9, 6, 8, 1, 4, 5, 2}
传递1,2,3:min_pos = 5, max_pos = 2, median_pos = 7, median = 5
swap (0, min_pos) -> {1, 7, 9, 6, 8, 3, 4, 5, 2}
swap (9, max_pos) -> {1, 7, 2, 6, 8, 3, 4, 5, 9}
swap (4, median_pos) -> {1, 7, 2, 6, 5, 3, 4, 8, 9}
现在below_pos = 0
above_pos = 8
。元素不是错位的。
接下来错位的是位置1处的7位。接下来错位的位置是位置6处的4位。
swap (1, 6) -> {1, 4, 2, 6, 5, 3, 7, 8, 9}
下面的错位是在第3位的6位。接下来错位在第5位是3位。
swap (3, 5) -> {1, 4, 2, 3, 5, 6, 7, 8, 9}
算法输出
{1,4,2,3,5,6,7,8,9}
答案 1 :(得分:0)
如果进行了许多更改和许多查找,您可以在O(log n sqrt(n))摊销时间内执行此操作。
最初,您对数组进行排序。然后,提取中值周围的sqrt(n)最小值,sort(n)最大值和sqrt(n)值。所以你会知道“有n1个元素&lt; = x1”(其中n1是关于sqrt(n)而x1是n1个最小的元素),“有n2个元素&lt; = x2”(其中n2是关于n / 2 - sqrt(n)/ n,x2是n2最小元素),“有n3个元素&lt; = x3”(其中n3约为n / 2 + sqrt(n)/ n,x3是n3 - 最小元素)和“有n4个元素&lt; = x4”,其中n4接近n - sqrt(n),n4是x4最小元素。您可以跟踪元素编号0到n1,编号n2到n3以及编号n4到n-1。
要获得最小值,最大值或中值,您需要检查sqrt(n)元素。
当您对数组元素进行更改,或添加或插入元素时,您可以根据发生的情况调整值n1,n2,n3和n4,以及数字0到n1,n2到n3的列表,和n4到n-1。在进行太多更改后,将更改数字n1,n2,n3,n4,以便搜索min,max,medium需要太长时间或者不再有任何用处。发生这种情况时,再次对数据进行排序。
顺便说一句。我认为堆积的想法会更好。
答案 2 :(得分:-1)
如果您有大量内存,可以使用两个来存储中位数和两个变量来存储最小值/最大值:
优点:
O(1)
更新; O(log N)
; 缺点:
C ++中有一个内置的STL函数可以帮助您轻松构建和更新堆:std::make_heap
,std::push_heap
和std::pop_heap
。
有关如何使用两个堆来查找中位数的更多详细信息,请参阅here。
嗯,你也可以变得更加棘手 - 使用两个向量来保存你的数据。在这种情况下,您只需要 N 内存,但您的数据将被拆分为两个向量。
答案 3 :(得分:-3)
O(n)似乎是你可以做的最好的排列数组,你做的方式似乎很好。
在最后一段中,您声明您对数组执行了某些操作,以便它再次以随机顺序排列,但不会添加任何新值。也许不是像某些人所说的那样创建堆,仅仅制作一个已安排数组的副本是不够的?
Pro:你只需要安排一次数组。
Con:你需要两倍的记忆。
答案 4 :(得分:-3)
绝对不能在O(N)中更快地完成它,因为你必须查看所有元素,甚至找到最小值。
当然,您可以讨论在O(N)复杂度内优化代码(即在 N 之前优化常量)。
或者你会在略微修改过的阵列上多次做同样的操作吗?