【发布时间】:2020-12-25 16:09:48
【问题描述】:
我试图将问题陈述总结如下::
给定n、k 和一个数组(列表)arr,其中n = len(arr) 和k 是set (1, n) inclusive 中的integer。
对于数组(或列表)myList,不公平和定义为myList 中所有可能对(每个组合有 2 个元素)之间的绝对差值的 sum。
解释:如果mylist = [1, 2, 5, 5, 6],则最小不公平和或MUS。请注意,元素在列表中的index 被认为是唯一的,而不是它们的值
MUS = |1-2| + |1-5| + |1-5| + |1-6| + |2-5| + |2-5| + |2-6| + |5-5| + |5-6| + |5-6|
如果你真的需要看问题陈述,那就是HERE
我的目标
给定n, k, arr(如上所述),从所有可能的子数组的不公平总和中找到Minimum Unfairness Sum,每个len(sub array) = k [这是让我们的生活变得轻松的好东西,我相信:)]
我尝试过的
嗯,这里有很多要补充的,所以我会尽量简短。
我的第一种方法是我使用itertools.combinations 来获取所有可能的组合并使用statistics.variance 检查它的spread of data(是的,我知道我真是一团糟)。
在你看到下面的代码之前,你认为这些方差和不公平总和是否完全相关(我知道它们是密切相关的),即minimum variance 的子数组必须是MUS 的子数组??
您只需检查LetMeDoIt(n, k, arr) 函数。如果需要MCVE,请查看下方第二个代码sn-p。
from itertools import combinations as cmb
from statistics import variance as varn
def LetMeDoIt(n, k, arr):
v = []
s = []
subs = [list(x) for x in list(cmb(arr, k))] # getting all sub arrays from arr in a list
i = 0
for sub in subs:
if i != 0:
var = varn(sub) # the variance thingy
if float(var) < float(min(v)):
v.remove(v[0])
v.append(var)
s.remove(s[0])
s.append(sub)
else:
pass
elif i == 0:
var = varn(sub)
v.append(var)
s.append(sub)
i = 1
final = []
f = list(cmb(s[0], 2)) # getting list of all pairs (after determining sub array with least MUS)
for r in f:
final.append(abs(r[0]-r[1])) # calculating the MUS in my messy way
return sum(final)
上面的代码对n<30 工作正常,但除此之外还引发了MemoryError。
在 Python 聊天中,Kevin 建议我尝试generator,即memory efficient(确实如此),但由于生成器也会动态生成这些组合,因为我们iterate 在它们之上,它应该花费超过 140 小时( :/) 对于 n=50,估计 k=8。
我在 SO HERE 上发布了与问题相同的问题(您可能想看看以正确理解我 - 它有讨论和融合的答案,这让我采用了我的第二种方法 - 一个更好的方法(我应该说fusion 的方法 xD))。
第二种方法
from itertools import combinations as cmb
def myvar(arr): # a function to calculate variance
l = len(arr)
m = sum(arr)/l
return sum((i-m)**2 for i in arr)/l
def LetMeDoIt(n, k, arr):
sorted_list = sorted(arr) # i think sorting the array makes it easy to get the sub array with MUS quickly
variance = None
min_variance_sub = None
for i in range(n - k + 1):
sub = sorted_list[i:i+k]
var = myvar(sub)
if variance is None or var<variance:
variance = var
min_variance_sub=sub
final = []
f = list(cmb(min_variance_sub, 2)) # again getting all possible pairs in my messy way
for r in f:
final.append(abs(r[0] - r[1]))
return sum(final)
def MainApp():
n = int(input())
k = int(input())
arr = list(int(input()) for _ in range(n))
result = LetMeDoIt(n, k, arr)
print(result)
if __name__ == '__main__':
MainApp()
这段代码非常适合n up to 1000(可能更多),但由于time out而终止(5秒是在线判断的限制:/)对于n超过10000(最大的测试用例有n=100000 )。
=====
您将如何解决这个问题以在给定的时间限制(5 秒)内处理所有测试用例? (问题在algorithm & dynamic programming 下列出)
(您可以参考一下
- successful submissions(py3, py2, C++, java) 关于这个问题的其他候选人 - 这样你就可以 向我和未来的访客解释这种方法)
- an editorial 由问题制定者解释如何解决问题
- a solution code 由问题制定者本人 (py2, C++)。
- Input data (test cases) and expected output
编辑1 ::
对于这个问题的未来访客,我到目前为止的结论是,variance 和 unfairness sum 与 perfectly 不相关(它们与 strongly 相关)这意味着在许多整数列表中,带有 minimum variance 的列表并不总是带有 @ 的列表987654370@。如果你想知道为什么,我实际上在数学堆栈交换HERE 上提出了一个单独的问题,其中一位数学家为我证明了它xD(值得一看,因为它出乎意料)
就整个问题而言,您可以阅读下面 archer 和 Attersson 的答案(仍在尝试找出一种天真的方法来执行此操作 - 不过现在应该不远了)
感谢您的任何帮助或建议:)
【问题讨论】:
-
我对这个(有趣的)问题有复杂的感觉,因为这是一个hackerrank挑战,而在StackOverflow上寻求帮助违背了挑战的目的......
-
"if mylist = [1, 2, 5, 5, 6], then [...]
MUS = |1-2| + |1-5| + |1-5| + |1-6| + |2-5| + |2-5| + |2-6| + |5-5| + |5-5|" 你确定你没有在最后错过+ |5-6| + |5-6|吗? -
@Stef 哦,这是一个错字:/ 感谢您指出这一点:)。已编辑。
-
请注意“子数组”被认为是a contiguous section of the array。您的意思是“子集”吗?
-
您链接到的社论指出,“在这个问题中,我们得到一个包含 N 个数字的列表,从中选择 K 个数字,以使不公平和最小化。”没有提到 K 数字必须是连续的。 K 个连续的数字是从 sorted 数组中选择的,这意味着它们在原始数组中不一定是连续的。在问题陈述中澄清这一点对您很重要。
标签: python arrays algorithm dynamic-programming