Python 3.x 从等于x的列表中返回数字的最大子集或值

Python 3.x 从等于x的列表中返回数字的最大子集或值,python-3.x,recursion,dynamic-programming,memoization,subset-sum,Python 3.x,Recursion,Dynamic Programming,Memoization,Subset Sum,我试图返回组成给定值总和的最大数,如果列表中有一个数字组成该值,则返回该值 numberlist = [0,1,2,3,4,5,8,16,32,64,128] def getSubsetOrSingle(x,listofvalues): if x in listofvalues: return x else: return list()# list of the biggest values available that make up x 我

我试图返回组成给定值总和的最大数,如果列表中有一个数字组成该值,则返回该值

numberlist = [0,1,2,3,4,5,8,16,32,64,128]

def getSubsetOrSingle(x,listofvalues):
    if x in listofvalues:
        return x
    else:
        return list()# list of the biggest values available that make up x
我能够匹配列表中x的值,比如你要通过

getSubsetOrSingle(128, numberlist)
它将返回128,但我希望通过208并从列表中返回最大可能值,如下所示:

>>> print(getSubsetOrSingle(208, numberlist))
>>> [16,64,128]
>>> print(getSubsetOrSingle(128, numberlist))
>>> 128
>>> print(getSubsetOrSingle(33, numberlist))
>>> [1,32]
>>> print(getSubsetOrSingle(136, numberlist))
>>> [8,128]

我会把这个问题分为两类来处理。检查目标编号是否与输入列表中的任何元素完全相等的情况可能非常容易实现。您所看到的另一种情况可以通过一种很好的动态编程/记忆方法来解决

让我们从一个缓慢的递归算法开始,然后我们可以将其转换为DP风格的递归。假设您要解决以下问题:

仅使用列表中的前k个数字,您可以使用的最大数字数量是多少

作为一个基本情况,如果k=0(也就是说,你开始使用零数字),那么你可以使用零数字使T=0,并且不可能以任何方式使T>0。我们将通过说您需要-&infinity;数字表明这是不可能的

现在,假设您要处理k>0个数字。在这种情况下,您有两种选择。一种选择是将第k个数字作为总数的一部分。如果这个数字是m,那么你需要使用尽可能多的数字,使用前k-1个数字来形成T-m。(只有在m≤ 另一个选择是不包括第k个数字,在这种情况下,您希望使用尽可能多的第一个k-1硬币来形成T

这里有一些粗略的伪代码。我假设向负无穷大中添加任何东西都会返回负无穷大:

function mostNumbersFor(numberList, k, T) {
    /* Base case: if T < 0, we can’t make T. */
    if (T < 0) return -infinity;

    /* Base case: if k = 0, we can only make T = 0. */
    if (k == 0) {
        return T == 0? 0 : -infinity;
    }

    /* Otherwise, we either include the current number, or we don’t.
     * We take the better of the two options.
     */
    return max(mostNumbersFor(numberList, k - 1, T),
               mostNumbersFor(numberList, k - 1, T - numberList[k - 1]) + 1);
}
你会得到最大数量的数字,加起来正好是T


现在,这种方法非常非常慢,因为它会进行各种重复的递归调用。但是,如果您添加了备忘录或动态编程来消除这些冗余调用,那么速度会快得多。具体地说,k只有O(n)个可能值(其中n是输入列表的长度),T参数只有O(W)个可能值,其中W是输入目标值。这使得整个运行时O(nW)在W中是伪多项式,对于W的小值,它在实践中可能非常快。

我将通过将其分为两种情况来处理这个问题。检查目标编号是否与输入列表中的任何元素完全相等的情况可能非常容易实现。您所看到的另一种情况可以通过一种很好的动态编程/记忆方法来解决

让我们从一个缓慢的递归算法开始,然后我们可以将其转换为DP风格的递归。假设您要解决以下问题:

仅使用列表中的前k个数字,您可以使用的最大数字数量是多少

作为一个基本情况,如果k=0(也就是说,你开始使用零数字),那么你可以使用零数字使T=0,并且不可能以任何方式使T>0。我们将通过说您需要-&infinity;数字表明这是不可能的

现在,假设您要处理k>0个数字。在这种情况下,您有两种选择。一种选择是将第k个数字作为总数的一部分。如果这个数字是m,那么你需要使用尽可能多的数字,使用前k-1个数字来形成T-m。(只有在m≤ 另一个选择是不包括第k个数字,在这种情况下,您希望使用尽可能多的第一个k-1硬币来形成T

这里有一些粗略的伪代码。我假设向负无穷大中添加任何东西都会返回负无穷大:

function mostNumbersFor(numberList, k, T) {
    /* Base case: if T < 0, we can’t make T. */
    if (T < 0) return -infinity;

    /* Base case: if k = 0, we can only make T = 0. */
    if (k == 0) {
        return T == 0? 0 : -infinity;
    }

    /* Otherwise, we either include the current number, or we don’t.
     * We take the better of the two options.
     */
    return max(mostNumbersFor(numberList, k - 1, T),
               mostNumbersFor(numberList, k - 1, T - numberList[k - 1]) + 1);
}
你会得到最大数量的数字,加起来正好是T


现在,这种方法非常非常慢,因为它会进行各种重复的递归调用。但是,如果您添加了备忘录或动态编程来消除这些冗余调用,那么速度会快得多。具体地说,k只有O(n)个可能值(其中n是输入列表的长度),T参数只有O(W)个可能值,其中W是输入目标值。这使得整个运行时O(nW)在W中是伪多项式,对于W的小值,它在实践中可能非常快。

请向我们展示您获取可能值的尝试如果列表始终为“0,1,2,4,8,…,128”,您可以将“x”作为二进制数。。。检查二进制数是否为1,你会得到你的'numberlist'Hey@GijsDenHollander它实际上不是一个二进制数列表,只是一个看起来像one@yklsga我正在研究它,我尝试使用max()函数并弹出列表中最大的元素并再次循环,但没有运气,因为它只会比较最大的元素,而不会比较较小的元素请向我们展示您获取可能值的尝试如果列表始终为“0,1,2,4,8,…,128”,则可以将“x”作为二进制数。。。检查二进制数是否为1,你会得到你的'numberlist'Hey@GijsDenHollander它实际上不是一个二进制数列表,只是一个看起来像one@yklsga我正在研究它,我尝试使用max()函数,弹出列表中最大的元素并再次循环,但没有运气,因为它只会比较最大的元素,而不会比较较小的元素