Arrays 无排序的顶K子集和
给定一个大小为N的数组,打印大小为K的所有子集Arrays 无排序的顶K子集和,arrays,algorithm,subset,Arrays,Algorithm,Subset,给定一个大小为N的数组,打印大小为K的所有子集(0我将这样解决此问题: for each count of elements to use for each possible sum for each starting index count of ways to get there (with or without that starting index) counts_by_count_by_sum_by_index = [ { #
(0我将这样解决此问题:
for each count of elements to use
for each possible sum
for each starting index
count of ways to get there (with or without that starting index)
counts_by_count_by_sum_by_index = [
{ # empty sets
0: [1, 1, 1, 1]
},
{ # 1 element sets
3: [1, 1, 1, 0],
6: [1, 0, 0, 0],
8: [1, 1, 0, 0],
9: [1, 1, 1, 1],
},
{ # 2 element sets
9: [1, 0, 0, 0],
11: [1, 1, 0, 0],
12: [1, 1, 1, 0],
14: [1, 0, 0, 0],
15: [1, 0, 0, 0],
17: [1, 1, 0, 0],
},
{ # 3 element sets
17: [1, 0, 0, 0],
18: [1, 0, 0, 0],
20: [1, 1, 0, 0],
23: [1, 0, 0, 0],
},
{ # 4 element sets
26: [1, 0, 0, 0]
}
]
对数组进行排序,让s
为前k
个元素的总和
使用函数生成等于s
的所有总和子集
找到最小的s2>s
,这样就有了一个子集,其总和等于s2
,使用
如果存在此类s2
,则设置s=s2
并转至步骤2。否则,停止
这里是Python中的一个实现:它按照和的顺序惰性地生成每个子集,因此您可以只获取它生成的第一个T子集
def子集的求和顺序(lst,k):
"""
返回生成k元素子集的生成器
对于lst,按其和的递增顺序。
"""
lst=已排序(lst)
s=总和(lst[:k])
max_s=总和(lst[-k:]
虽然s不是无:
_和(lst,k,s)的子集_的收益率
s=范围内的最小和(lst、k、s+1、最大)
def_和的子集(lst,k,s,t=(),i=0):
"""
返回生成元组t+tt的生成器,其中tt
是lst[i:]的k元素子集,其和为s
子集是按字典顺序产生的
必须对lst进行排序。
"""
如果k<0:
提升值错误()
elif k==0:
如果s==0:
产量t
其他:
对于范围(i,len(lst)-k+1内的j:
如果和(lst[j:j+k])>s:break
v=lst[j]
s2=s-v
t2=t+(v,)
_和(lst,k-1,s2,t2,j+1)的子集_的收益率
定义范围内的最小和(lst、k、min、max、i=0):
"""
返回最小的s,使min_s一种方法涉及动态规划
首先,想象一下,如果我们有一个如下所示的数据结构:
for each count of elements to use
for each possible sum
for each starting index
count of ways to get there (with or without that starting index)
counts_by_count_by_sum_by_index = [
{ # empty sets
0: [1, 1, 1, 1]
},
{ # 1 element sets
3: [1, 1, 1, 0],
6: [1, 0, 0, 0],
8: [1, 1, 0, 0],
9: [1, 1, 1, 1],
},
{ # 2 element sets
9: [1, 0, 0, 0],
11: [1, 1, 0, 0],
12: [1, 1, 1, 0],
14: [1, 0, 0, 0],
15: [1, 0, 0, 0],
17: [1, 1, 0, 0],
},
{ # 3 element sets
17: [1, 0, 0, 0],
18: [1, 0, 0, 0],
20: [1, 1, 0, 0],
23: [1, 0, 0, 0],
},
{ # 4 element sets
26: [1, 0, 0, 0]
}
]
编写代码来填写此信息并不难。对于[6,8,3,9]
您将得到如下结果:
for each count of elements to use
for each possible sum
for each starting index
count of ways to get there (with or without that starting index)
counts_by_count_by_sum_by_index = [
{ # empty sets
0: [1, 1, 1, 1]
},
{ # 1 element sets
3: [1, 1, 1, 0],
6: [1, 0, 0, 0],
8: [1, 1, 0, 0],
9: [1, 1, 1, 1],
},
{ # 2 element sets
9: [1, 0, 0, 0],
11: [1, 1, 0, 0],
12: [1, 1, 1, 0],
14: [1, 0, 0, 0],
15: [1, 0, 0, 0],
17: [1, 1, 0, 0],
},
{ # 3 element sets
17: [1, 0, 0, 0],
18: [1, 0, 0, 0],
20: [1, 1, 0, 0],
23: [1, 0, 0, 0],
},
{ # 4 element sets
26: [1, 0, 0, 0]
}
]
如果您有更多的元素,此数据结构可以以伪多项式的方式变大,但可以扩展。具体来说,O((元素大小)*(集合大小)^3)
使用这种数据结构,很容易编写按和搜索,然后按字典顺序(按使用的索引)递归查找解决方案
如果你愿意,你也可以找到,比如说,第一百万个解是什么,而不必生成之前的解。只是一个想法。如果K
是3,你取输入数组中最小的4个元素,你可以从这4个元素中选择3个,得到4个最小的子集。取5个元素,你可以形成最小的5C3子集。@无法使用的用户3386109,例如[3,6,7,8,9]
-您的算法将在3,6,9
之前生成6,7,8
。我不确定我错过了哪一步。我想说的是,对于某些输入,可能有一个子集包含数组的最后一个元素,它比不包含数组的第一个元素的任何子集都小,因此任何基于yieldin的算法数组前缀不断增加的g子集是行不通的。你说的“取输入数组中最小的4个元素,通过选择其中的3个,你将得到4个最小的子集”是错误的。我要强调的是,对于某些输入,可能有一个子集包含数组的最后一个元素"我假设你的意思是,对于某些输入,可以有一个子集包含数组中最大的元素。对吗@kaya3@kaya3好的,我最初的想法是,在一般情况下,不需要数组中的最大元素。例如,如果k=3
和T=10
和N=100
,则不需要数组的第100个元素。需要考虑的是,“你需要数组的多少个元素?”这是一个很好的解决方案,但提前生成所有可能的和相当于在最坏的情况下生成所有(n选择k)组合,不是吗?可以用“准时”编写此算法使用优先级队列实现数据结构。这听起来很有趣。但我必须花很多时间思考如何使其工作。我肯定遗漏了一些东西。这似乎效率极低。对于1000个元素的数组,这将如何工作,并且您需要找到长度为100的前100万个子集,以及最小的总和。对于e例如,你对每一个可能的总和都有,这意味着所有的总和都已生成。我们不是要避免这种情况吗?我非常清楚@btilly的强大,我真的相信我在这里缺少一些东西。@JosephWood我认为t=1000000
不适合这个(不是很小)约束。@JosephWood在我说的优先级队列评论中,但我必须对如何使其工作进行大量思考。这意味着我对如何执行它有很好的想法,但实际实现是复杂的。如果您想尝试一下,您需要用返回的流替换k元素集
s对(值,计数)
。该流应该使用生成的值(如果存在),如果不存在则生成更多。生成更多应该是从优先级队列中选取部分计算。