列表定义如下:[1, 2, 3]
及其子列表是:
[1], [2], [3],
[1,2]
[1,3]
[2,3]
[1,2,3]
给定示例3的K,任务是找到子列表的最大长度,其中元素之和小于等于k。
我知道python中的itertools
但是它会导致较大列表的分段错误。有没有其他有效的算法来实现这一目标?任何帮助,将不胜感激。
我的代码是允许的:
from itertools import combinations
def maxLength(a, k):
#print a,k
l= []
i = len(a)
while(i>=0):
lst= list(combinations(sorted(a),i))
for j in lst:
#rint list(j)
lst = list(j)
#print sum(lst)
sum1=0
sum1 = sum(lst)
if sum1<=k:
return len(lst)
i=i-1
答案 0 :(得分:1)
据我所知(因为您将子数组视为初始数组的任何项),您可以使用 greedy 算法,其复杂度为O(N*log(N))
(你必须对数组进行排序):
1. Assign entire array to the sub array
2. If sum(sub array) <= k then stop and return sub array
3. Remove maximim item from the sub array
4. goto 2
实施例
[1, 2, 3, 5, 10, 25]
k = 12
解决方案
sub array = [1, 2, 3, 5, 10, 25], sum = 46 > 12, remove 25
sub array = [1, 2, 3, 5, 10], sum = 21 > 12, remove 10
sub array = [1, 2, 3, 5], sum = 11 <= 12, stop and return
作为替代方案,您可以从空子数组开始,并将项目从最小值添加到最大值,而总和小于或等于k
:
sub array = [], sum = 0 <= 12, add 1
sub array = [1], sum = 1 <= 12, add 2
sub array = [1, 2], sum = 3 <= 12, add 3
sub array = [1, 2, 3], sum = 6 <= 12, add 5
sub array = [1, 2, 3, 5], sum = 11 <= 12, add 10
sub array = [1, 2, 3, 5, 10], sum = 21 > 12, stop,
return prior one: [1, 2, 3, 5]
答案 1 :(得分:0)
看,为了产生功率设置需要O(2 ^ n)时间。这很糟糕。您可以使用动态编程方法。
在此处查看算法。 http://www.geeksforgeeks.org/dynamic-programming-subset-sum-problem/
是的,https://www.youtube.com/watch?v=s6FhG--P7z0(Tushar很好地解释了一切):D
答案 2 :(得分:0)
您可以使用@Apy链接到的dynamic programming solution。这是一个Python示例:
def largest_subset(items, k):
res = 0
# We can form subset with value 0 from empty set,
# items[0], items[0...1], items[0...2]
arr = [[True] * (len(items) + 1)]
for i in range(1, k + 1):
# Subset with value i can't be formed from empty set
cur = [False] * (len(items) + 1)
for j, val in enumerate(items, 1):
# cur[j] is True if we can form a set with value of i from
# items[0...j-1]
# There are two possibilities
# - Set can be formed already without even considering item[j-1]
# - There is a subset with value i - val formed from items[0...j-2]
cur[j] = cur[j-1] or ((i >= val) and arr[i-val][j-1])
if cur[-1]:
# If subset with value of i can be formed store
# it as current result
res = i
arr.append(cur)
return res
ITEMS = [5, 4, 1]
for i in range(sum(ITEMS) + 1):
print('{} -> {}'.format(i, largest_subset(ITEMS, i)))
输出:
0 -> 0
1 -> 1
2 -> 1
3 -> 1
4 -> 4
5 -> 5
6 -> 6
7 -> 6
8 -> 6
9 -> 9
10 -> 10
在上面arr[i][j]
True
,如果设置值为i
,则可以从items[0...j-1]
中选择。自然arr[0]
只包含True
个值,因为可以选择空集。类似地,对于所有连续的行,第一个单元格是False
,因为不能存在具有非零值的空集。
对于其余的细胞,有两种选择:
i
的子集,即使不考虑item[j-1]
,则值为True
i - items[j - 1]
,那么我们可以向其中添加项目,并使用值为i
的子集。答案 3 :(得分:0)
假设一切都是积极的。 (处理底片是对此的简单扩展,留给读者作为练习)。对于所描述的问题,存在O(n)算法。使用O(n)中位数选择,我们根据中位数对数组进行分区。我们找到左侧的总和。如果该值大于k,则我们不能取所有元素,因此必须在左半部分重新尝试取较小的元素。否则,我们从k中减去左半部分的总和,然后在右半部分上递归,以查看可以容纳多少个元素。
基于中位数选择对数组进行分区并仅对其中一半进行重复操作,可得到n + n / 2 + n / 4 + n / 8 ..的运行时间,其几何总和为O(n)。