簡體   English   中英

獲取加起來為數字“n”的數字列表(使用數字重復)——如何考慮多次使用相同數字的情況?

[英]Get a list of numbers that adds up to a number "n" (using repetition of number) - how would one consider the case of using same number multiple times?

def getList(n, input_list, caching_list):

假設數字可以重復,function 應該返回一個列表,該列表使用 input_list 中的數字加起來為數字“n”。 希望使用遞歸。

當前代碼:

def getList(n, input_list, caching_list):
  if n == 0 :
    return caching_list
  if n < 0 or len(input_list) == 0:
    return []

  for i in input_list:
    if find_sum(n-i,input_list,caching_list) == caching_list:
        caching_list.append(i)
        return caching_list
  return []

例如 n = 13,input_list= [2,3,5] 應該導致 [2,2,2,2,2,3] 或 [5,5,2] 或任何與 13 相加的結果。

只需使用一個數字 1 次就可以做到這一點,但是如何考慮多次使用相同數字的情況呢?

使用遞歸,這可以使用深度優先搜索 (DFS) 算法來解決,但它可以拋出RecursionError: maximum recursion depth exceeded in comparison

def find(n2, plist):
    result = []
    def find2(n):
        if n == 0:
            return True
        if n < 0:
            return False
        for p in plist:
            if find2(n-p):
                result.append(p)
                return True
    find2(n2)
    return result
            
print(find(17, [2,3,5]))       # [3, 2, 2, 2, 2, 2, 2, 2]
print(find(7, [3,5]))          # []
print(find(77777, [3,5,7,11])) # recursion error

為了消除遞歸錯誤,可以將 recursive DFS 重寫為iterative DFS

我發現itertools對於這樣的東西非常方便。 我相信有更好的方法可以做到這一點,但這可能會讓你想要你需要:

import itertools

def find_sum(n, p_list):
    max_len = n // min(p_list)
    min_len = n // max(p_list)

    for i in range(min_len, max_len+1):
        I = itertools.combinations_with_replacement(p_list, i)
        for j in I:
            if(sum(j) == n):
                return(list(j))
    return([])

print(find_sum(17,[2,3,5]))
# [2, 5, 5, 5]
print(find_sum(7, [3, 5]))
# []

您可以輕松更改代碼以提供所有組合。


def find_sum(n, p_list):
    max_len = n // min(p_list)
    min_len = n // max(p_list)
    answers = []
    for i in range(min_len, max_len+1):
        I = itertools.combinations_with_replacement(p_list, i)
        for j in I:
            if(sum(j) == n):
                answers.append(list(j))
    return(answers)
find_sum(17,[2,3,5])
#[[2, 5, 5, 5], [2, 2, 3, 5, 5], [3, 3, 3, 3, 5], [2, 2, 2, 3, 3, 5], [2, 3, 3, 3, 3, 3], [2, 2, 2, 2, 2, 2, 5], [2, 2, 2, 2, 3, 3, 3], [2, 2, 2, 2, 2, 2, 2, 3]]

關於@dantebarba 的評論,我還沒有真正了解它如何擴展以解決大問題,並且可能有更有效的方法。

這 3 行代碼應該引起一些危險信號:

if find_sum(n-i,p,p_list,sum_list) == sum_list:
    sum_list.append(i)
    return sum_list

您有一個遞歸的 function 將其結果存儲在sum_list中,對其進行修改,並根據其值進行相等性檢查。 這使您的程序極難推理。 如果在等號周圍交換 arguments,行為會改變嗎? 我不知道。

通常,您的遞歸程序應盡量避免將其結果作為參數傳遞。 既然那個if語句實際上是在問我們是否可以得到一定的總和,為什么不把它分解成一個單獨的 function 呢?

def can_sum(n, p_list, cache={}):
    if n in cache:
        return cache[n]
    if n == 0:
        return True
    if n < 0:
        return False
    return any(can_sum(n-p, p_list) for p in p_list)

您想使用某種緩存(否則,您的程序是指數時間的),如果可以使用外部庫,則functools.cache更可取,但這可以完成工作。

你的find_sum function 應該如何在不將結果作為參數傳遞的情況下返回結果? 只需將您的價值添加到最后,就像您的代碼一樣:

def find_sum(n, p_list):
    for p in p_list:
        if can_sum(n-p, p_list):
            return find_sum(n-p, p_list) + [p]
    return []

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM