【问题标题】:recursion on each element of array递归数组的每个元素
【发布时间】:2018-07-11 02:46:15
【问题描述】:

我有一个整数 S 和一个整数集合 A。我需要从集合中找到一组整数,其中这些整数的总和等于 S。它可以是 1 个整数或 50 - 没关系。

我正在尝试这样做:

我有一个数组 res 和一个数组 grp

res 以 [0] 开头,grp 是最初给定的集合,S 是我们要查找的总和,S 是全局的

我的函数需要 (res, grp)

我想这样做:(和示例)

-

当res元素之和等于S时停止

但是我很讨厌递归,我不知道我应该做什么

这是我的代码

S = 7
grp = [0,5,6,4,3]

def sumFinder(res,grp):
    if grp == []:
        return grp #in case no pair was found [] is returned 
    if sum(res) == S:
        return res
    for i in range (0,len(grp)):
        print(res)
        print(grp[i])
        res += [grp[i]]
        newgrp = grp[:i]
        newgrp += grp[i+1:]
        return sumFinder(res,newgrp)

 print(sumFinder([0],grp))

更新:

谢谢大家的回答 感谢 englealuze 让我对解决问题有了更好的了解,谢谢你,我明白了:

1 - 这是为了找到第一个组合并返回它(这是我的目标)

grp = [1,0,1,0,1,2,6,2,3,5,6,7,8,9,2,1,1,9,6,7,4,1,2,3,2,2]
S = 55
grps = []

def findCombination(comb,grp):
    for i in range (0,len(grp)):
        comb += [grp[i]]
        newgrp = grp[:i]
        newgrp += grp[i+1:]

        if sum(comb) == S:
            return comb

        if newgrp not in grps:
            grps.append(newgrp)
            res = findCombination([],newgrp)
            if res != None:
                return res

print(findCombination([],grp))

2- 这是为了找到所有的组合:(这是 englealuze 谈到的问题,但我不太了解他的方法,即使它看起来更好)

grp = [1,0,1,1,9,6,7,4,1,2,3,2,2]
S = 12
grps = []
combinations = []

def findAllCombinations(comb,grp):
    global combinations
    for i in range (0,len(grp)):
        comb += [grp[i]]
        newgrp = grp
        newgrp = grp[:i]
        newgrp += grp[i+1:]

        if sum(comb) == S and tuple(comb) not in combinations:
            combinations.append(tuple(comb))

        if newgrp not in grps:
            grps.append(newgrp)
            findAllCombinations([],newgrp)

findAllCombinations([],grp)
print(combinations)

我现在唯一的问题是当 S > 50(在第一个)时,找到答案需要更长的时间

你们能给我什么建议来改进这两种算法?

【问题讨论】:

  • 你有什么问题?
  • 你不应该在这里首先使用递归,子集和问题通常可以用动态规划快速解决。
  • 关键问题是你在一个循环中使用'return'。这导致循环将运行一次而不是 range(0,len(grp))
  • @WillemVanOnsem 我知道,但我从未使用过动态编程,我还在学习递归,我不应该先学习吗?

标签: python arrays list recursion dynamic-programming


【解决方案1】:

以下代码有效(删除循环中的“直接返回”,改为有条件的“返回”)。

但我认为这不是一个好的解决方案。你需要改进你的算法。

PS:此代码也只会返回一个匹配项而不是全部。

S = 7
grp = [0,3,6,4,6]

result = []

def sumFinder(res,grp, result):
    for i in range (0,len(grp)):
        temp = list(res) #clone res instead of direct-reference
        if grp == [] or not temp:
            return grp #in case no pair was found [] is returned
        if sum(temp) == S:
            result.append(tuple(temp))
            return temp
        temp.append(grp[i])
        newgrp = grp[:i] + grp[i+1:]
        sumFinder(list(temp),newgrp, result)

sumFinder([0], grp, result)
print result

测试用例:

S = 7
grp = [0,3,6,4,6]
result = [(0, 0, 3, 4), (0, 0, 4, 3), (0, 3, 0, 4), (0, 3, 4), (0, 4, 0, 3), (0, 4, 3)]
[Finished in 0.823s]

【讨论】:

  • 非常感谢,但是代码在S = 7 grp = [0,3,6,4,6]的情况下不起作用
  • @HammiCloud,这个问题是因为'res被用作一个参考而不是一个副本;检查这个:Python Reference&Copy'。所以添加了一行 ('temp=list(res)') 来解决这个问题。
【解决方案2】:

我将向您展示如何思考这个问题以及如何从一般意义上解决此类问题,而不仅仅是提供代码。

首先,让我们重新表述您的问题。实际上,您想要的是对于给定的一组数字,找到该组内满足特定条件的组合。因此,您可以将问题分解为 2 个不同的步骤。

  1. 找到你的所有组合
  2. 过滤掉满足特定条件的组合

让我们想想如何递归地解决第一个任务。请记住,如果可以通过递归方式解决问题,则通常意味着您的数据中存在一些递归模式,并且通常可以通过非常简单明了的方式解决。如果你最终得到一个混乱的递归解决方案,这几乎意味着你走错了方向。

让我们先看看您的数据模式。如果你有一个非常小的集合 (1, 2),那么这个集合之外的组合是

1
2
1, 2

让我们在集合中增加一个成员,(1, 2, 3)。对于这个更大的集合,所有的组合都是

1       | 1, 3
2       | 2, 3
1, 2    | 1, 2, 3
        | 3

让我们看看更大的集合(1、2、3、4)。可能的组合是

1       1, 3       | 1, 3, 4
2       2, 3       | 2, 3, 4
1, 2    1, 2, 3    | 1, 2, 3, 4
        3          | 3, 4
                   | 4

现在您看到了一些有趣的东西,一个较大集合的组合是较小集合加上附加到每个先前组合的附加元素以及附加元素本身的组合。

假设你已经得到了具有一定大小的集合的所有组合的解,则可以从这个解中导出更大集合的解。这自然形成了递归。您可以将这个简单的英语直接翻译成递归代码,如下所示

# assume you have got all combinations of a smaller set -> combinations(smaller(L))
# the solution of your bigger set can be directly derived from it with known new element
def combinations(L):
    if L == []:
        return []
    else:
        return next_solution(combinations(smaller(L)), newitem(L))

请注意我们如何将解决较大问题的任务分解为解决较小问题。您需要以下辅助函数

# in your case a smaller set is just the new set drop one element
def smaller(L):
    return L[1:]

# the new element would be the first element of new set
define newitem(L):
    return L[0]

# to derive the new solution from previous combinations, you need three parts
# 1. all the previous combinations -> L
# 2. new item appending to each previous combination -> [i + [newelement] for i in L]
# 3. the new item itself [[newelement]]
def next_solution(L, newelement):
    return L + [i + [newelement] for i in L] + [[newelement]]

现在我们知道如何从一组中取出所有组合。 然后要过滤它们,您不能只将过滤器直接插入递归步骤,因为我们依靠我们之前的解决方案来递归地构建结果列表。简单的方法是过滤列表,同时获得所有组合的完整结果。

你最终会得到这样的解决方案。

def smaller(L):
  return L[1:]

def newitem(L):
  return L[0]

def next_solution(L, newelement):
  return L + [i + [newelement] for i in L] + [[newelement]]

def filtersum(L, N, f=sum):
  return list(filter(lambda x: f(x)==N, L))

def combinations(L):
  if L == []:
    return []
  else:
    return next_solution(combinations(smaller(L)), newitem(L))

def filter_combinations(L, N, f=filtersum):
  return f(combinations(L), N)

print(filter_combinations([0,5,6,4,3], 7))
# -> [[3, 4], [3, 4, 0]]

您可以通过在每次递归调用中过滤掉总和大于您定义的值的组合来节省一些计算,例如

def combinations(L):
  if L == []:
    return []
  else:
    return next_solution(list(filter(lambda x: sum(x) <=5, combinations(smaller(L)))), newitem(L))

print(combinations([1,2,3,4]))
# -> [[4], [3], [3, 2], [2], [4, 1], [3, 1], [3, 2, 1], [2, 1], [1]]

事实上,递归会有不同的方法,这取决于你如何将问题分解为更小的问题。存在一些更聪明的方法,但我上面展示的方法是解决此类问题的典型且通用的方法。

我有用这种方式解决其他问题的例子

Python: combinations of map tuples

【讨论】:

  • 这对我来说真的很难理解,也许我只是愚蠢..你有什么书或教程我可以阅读以提高我的技能,我也刚开始学习python,那有什么用这个做什么? for i in L 这不是 for 循环你怎么会这样使用它 return L + [i + [newelement] for i in L] + [[newelement]]
【解决方案3】:

你能告诉我你是在哪里发现这个问题的吗?我喜欢解决这类问题,Bdw 这是我的方法:

a=[[[0],[0,5,6,4,3]]]

s=7

def recursive_approach(array_a):
    print(array_a)
    sub=[]
    for mm in array_a:
        array_1 = mm[0]
        array_2 = mm[1]
        if sum(array_2)==s:
            return "result is",array_2
        else:
            track = []
            for i in range(len(array_2)):
                c = array_2[:]
                del c[i]

                track.append([array_1 + [array_2[i]], c])
            sub.append(track)
    print(sub)
    return recursive_approach(sub[0])





print(recursive_approach(a))

输出:

[[[0], [0, 5, 6, 4, 3]]]
[[[[0, 0], [5, 6, 4, 3]], [[0, 5], [0, 6, 4, 3]], [[0, 6], [0, 5, 4, 3]], [[0, 4], [0, 5, 6, 3]], [[0, 3], [0, 5, 6, 4]]]]
[[[0, 0], [5, 6, 4, 3]], [[0, 5], [0, 6, 4, 3]], [[0, 6], [0, 5, 4, 3]], [[0, 4], [0, 5, 6, 3]], [[0, 3], [0, 5, 6, 4]]]
[[[[0, 0, 5], [6, 4, 3]], [[0, 0, 6], [5, 4, 3]], [[0, 0, 4], [5, 6, 3]], [[0, 0, 3], [5, 6, 4]]], [[[0, 5, 0], [6, 4, 3]], [[0, 5, 6], [0, 4, 3]], [[0, 5, 4], [0, 6, 3]], [[0, 5, 3], [0, 6, 4]]], [[[0, 6, 0], [5, 4, 3]], [[0, 6, 5], [0, 4, 3]], [[0, 6, 4], [0, 5, 3]], [[0, 6, 3], [0, 5, 4]]], [[[0, 4, 0], [5, 6, 3]], [[0, 4, 5], [0, 6, 3]], [[0, 4, 6], [0, 5, 3]], [[0, 4, 3], [0, 5, 6]]], [[[0, 3, 0], [5, 6, 4]], [[0, 3, 5], [0, 6, 4]], [[0, 3, 6], [0, 5, 4]], [[0, 3, 4], [0, 5, 6]]]]
[[[0, 0, 5], [6, 4, 3]], [[0, 0, 6], [5, 4, 3]], [[0, 0, 4], [5, 6, 3]], [[0, 0, 3], [5, 6, 4]]]
[[[[0, 0, 5, 6], [4, 3]], [[0, 0, 5, 4], [6, 3]], [[0, 0, 5, 3], [6, 4]]], [[[0, 0, 6, 5], [4, 3]], [[0, 0, 6, 4], [5, 3]], [[0, 0, 6, 3], [5, 4]]], [[[0, 0, 4, 5], [6, 3]], [[0, 0, 4, 6], [5, 3]], [[0, 0, 4, 3], [5, 6]]], [[[0, 0, 3, 5], [6, 4]], [[0, 0, 3, 6], [5, 4]], [[0, 0, 3, 4], [5, 6]]]]
[[[0, 0, 5, 6], [4, 3]], [[0, 0, 5, 4], [6, 3]], [[0, 0, 5, 3], [6, 4]]]
('result is', [4, 3])

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2020-11-03
  • 1970-01-01
  • 2016-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多