这是一个算法问题:
Input是一个具有非重复正整数的数组。找到一个中位数最大的连续子数组(大小> 1)。
例如:输入:[100、1、99、2、1000],输出应为(1000 + 2)/ 2 = 501的结果
我可以提出蛮力解决方案:尝试从2->数组大小的所有长度中找到最大中值。但这似乎太慢了。我还尝试在此问题上使用两个指针,但不确定何时向左和向右移动指针。
有人有更好的主意来解决这个问题吗?
答案 0 :(得分:5)
tl; dr-我们可以证明答案的长度必须为2或3,然后才是检查所有可能性的线性时间。
让我们说输入为A
,最小的子数组中位数最大为a
。最大中位数是a
中的单个元素或一对元素的平均值。请注意,a
中每个大于中位数最大元素的元素只能与小于中位数最小元素的元素相邻(否则,可以选择这样的一对作为子数组以形成更大的中位数)。
如果a
的任一端都有一对不包含中位数元素的元素,则可以将其从a
中消除而不会影响中位数,这是一个矛盾。
如果a
的任一端小于中位数的最小元素,则消除它会增加中位数,这是一个矛盾。
因此a
的每个末端要么是中位数的一个元素,要么大于中位数的最大元素(因为它大于中位数的最小elt,但不等于中位数的最大elt)
因此a
的每个末端都是中位数的一个元素,因为否则,我们将有一个元素大于与中位数Elt相邻的中位数的元素,从而形成更大的中位数。
如果a
为奇数,则其长度必须为3,因为任何较大的奇数长度都可以从a
的最远离中位数的结尾处删除2,而不会更改中位数。
如果a
是偶数,则它的长度必须为2,因为由中位数的元素预定的任何更大的偶数长度以及内部元素在中位数之间交替变小或大于中位数,必须使其中一个元素相邻比中位数的其他元素大的元素,形成了更大的中位数。
该证明大纲可以进行一些编辑,但是无论如何,得出的结论是,包含最大中位数的最小数组的长度必须为2或3。
鉴于此,请在线性时间内检查每个此类子数组。 O(n)。
答案 1 :(得分:2)
这是算法的Python实现,可以解决O(n)
中的问题:
import random
import statistics
n = 50
numbers = random.sample(range(n),n)
max_m = 0;
max_a = [];
for i in range(2,3):
for j in range(0,n-i+1):
a = numbers[j:j+i]
m = statistics.median(a)
if m > max_m:
max_m = m
max_a = a
print(numbers)
print(max_m)
print(max_a)
这是蛮力算法(O(n ^ 3))的一种变体,仅执行长度为2或3的子数组的搜索。原因是对于大小为n
的每个数组,存在一个具有相同或改进中位数的子数组。递归地应用此推理,我们可以将子数组的大小减小到2或3。因此,通过仅查看大小为2或3的子数组,可以确保获得具有最大中位数的子数组。 / p>
操作如下:如果对于连续的子数组(在开始或结尾处),至少有一半的元素低于中位数(或低于构成中位数的两个值)就是这种情况),请删除它们以改善或至少保留中位数。
如果在所有子阵列中,总是在中位数以上或等于中位数至少有一个元素低于下位数,那么将出现一个点,其中子阵列的大小将为中位数的大小。在这种情况下,这意味着补数将在中位数以下包含更多元素,因此,我们可以简单地删除补码并改善(或保留)中位数。因此,我们始终可以执行该操作。对于n=3
,可能需要删除2或3个元素才能执行操作,这是不允许的。在这种情况下,结果就是列表本身。