【问题标题】:Largest Subset whose sum is less than equal to a given sum总和小于等于给定总和的最大子集
【发布时间】:2020-02-16 06:33:31
【问题描述】:

列表定义如下:[1, 2, 3]

它的子列表是:

[1], [2], [3],  
[1,2]  
[1,3]
[2,3]  
[1,2,3]

给定K,例如3,任务是找到元素总和小于等于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

【问题讨论】:

标签: python arrays algorithm powerset


【解决方案1】:

您可以使用@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,因为不能有非零值的空集。

对于其余的单元格,有两个选项:

  1. 如果已经有一个值为i 的子集,即使不考虑item[j-1],该值为True
  2. 如果有一个值为i - items[j - 1] 的子集,那么我们可以向其中添加项目并拥有一个值为i 的子集。

【讨论】:

  • 你能解释一下这里发生了什么吗?
  • @Aditya 将 cmets 添加到代码和简短说明中。
【解决方案2】:

据我所知(因为您将子数组视为初始数组的 任何项目)您可以使用具有O(N*log(N)) 复杂度的 greedy 算法(您有对数组进行排序):

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       

作为替代方案,您可以从 empty 子数组开始,然后在 sum 小于或等于 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,1,2,3,4] 假设整个数组是 [1,1,2,3,4,5,10, 25] sum=11
  • @Aditya:对不起,不要关注你。那么预期的结果是什么?是的,在[1,1,2,3,4,5,10,25]k = 12 的情况下,子数组[1,1,2,3,4] 是最长的一个,使得sum(sub array) &lt;= k(其中之一,因为[1,1,2,3,5] 是另一个示例)。
  • 但是你必须对数组进行排序。复杂度上升到 nlogn。
  • 使用 len() 函数。
  • @Apy:如果k &gt;= 0,贪婪方法将适用于任何项目;万一k &lt; 0 只删除实现会做(但不是加起来的替代方案)
【解决方案3】:

看,生成幂集需要 O(2^n) 时间。这很糟糕。您可以改为使用动态编程方法。

在此处查看算法。 http://www.geeksforgeeks.org/dynamic-programming-subset-sum-problem/

是的,https://www.youtube.com/watch?v=s6FhG--P7z0(Tushar 很好地解释了一切):D

【讨论】:

  • 我去看看。
  • 图沙尔来救场了? :D
  • 实际上不会导致元素的总和必须小于或等于。我已经检查了确切总和的极客极客解决方案。不过还在寻找。
  • @Aditya 你能给我一些测试用例吗?
  • [1], [2], [3]. [2,3], [1,3], [1,2], [1,2,3] k =3 最终答案是 2,因为 [1,2] 的总和为 3,并且长度最大。
【解决方案4】:

假设一切都是积极的。 (处理否定是对此的简单扩展,留给读者作为练习)。对于所描述的问题,存在一个 O(n) 算法。使用 O(n) 中值选择,我们根据中值对数组进行分区。我们找到左边的总和。如果它大于 k,那么我们不能取所有元素,因此我们必须在左半边递归以尝试取更小的集合。否则,我们从 k 中减去左半部分的总和,然后我们在右半部分递归,看看我们可以再取多少元素。

基于中值选择对数组进行分区并仅在其中的一半上重复产生 n+n/2 +n/4 +n/8.. 的运行时间,其几何总和为 O(n)。

【讨论】:

    猜你喜欢
    • 2021-06-04
    • 2013-08-06
    • 2017-01-10
    • 2016-05-27
    • 2014-08-07
    • 2022-10-12
    • 1970-01-01
    • 1970-01-01
    • 2018-08-10
    相关资源
    最近更新 更多