【问题标题】:Longest chain of elements from list in PythonPython中列表中最长的元素链
【发布时间】:2012-05-19 21:27:19
【问题描述】:

我有一个国家列表,我希望拥有最长的国家路径,其中每个国家选择必须以结束前一个元素的相同字母开头

nations = ['albania','andorra','austria','belarus','belgium','bosnia and herzegovina',
      'bulgaria','croatia','czech republic','denmark','estonia',  
      'finland','france','germany','greece','hungary',
      'iceland','ireland','italy','latvia','liechtenstein','lithuania','luxembourg',
      'macedonia','malta','moldova','monaco','montenegro','netherlands', 
      'norway','poland','portugal','romania','russia',  
      'san marino','serbia','slovakia','slovenia','spain','sweden', 'switzerland',
      'ukraine','united kingdom','vatican city'] 

chain('spain')
>>>['spain', 'netherlands', 'slovenia', 'andorra', 'austria', 'albania']

这个方法我试过了,还是不行

def chain(naz):
    initial = naz[-1]
    initials=[]
    res = set()
    res.add(naz)
    for i in nations:
        if i.startswith(initial):
            initials.append(i)
    for j in initials:
        nations.remove(j)
        res.add(j)
        chain(j)
    return res

有什么建议吗?

【问题讨论】:

  • 在什么情况下不起作用?
  • 如果我保留 countries.remove(j),错误是 ValueError: list.remove(x): x not in list,如果我删除那段代码 RuntimeError: 调用时超出最大递归深度一个 Python 对象
  • 请在您的问题中为这两个错误提供完整的堆栈跟踪,并使用注释来标识所涉及的代码行。

标签: python longest-path


【解决方案1】:

我也选择了递归下降。不确定动态编程是否适合这个,因为我们会修改列表。稍微更紧凑,并且不需要在调用链之前从列表中删除开始。 :-)

def chain(start, countries):
    remaining = list(countries)
    del remaining[remaining.index(start)]
    possibles = [x for x in remaining if x[:1] == start[-1:]]
    maxchain = []
    for c in possibles:
        l = chain(c, remaining)
        if len(l) > len(maxchain):
            maxchain = l
    return [start] + maxchain

这样打电话。 :-)

>>> chain('spain', nations)
['spain', 'netherlands', 'serbia', 'albania', 'andorra', 'austria']

【讨论】:

    【解决方案2】:

    这里有一些cmets:

    • 您希望返回路径。所以这是一个有序的集合,不是吗?您可能不应该将集合用于 res,因为集合是无序的
    • 你知道la长度还是返回的路径?不,你没有。所以你可能在某个地方需要while
    • i.startswith(initial) 仅当 i 以整个初始单词开头时才为真。你可能不想要这个
    • 您尝试使用递归方法。但是,您不收集结果。递归调用暂时没用
    • nations 是全局变量,不好

    编辑

    可能会出现您评论中描述的错误,因为您的递归调用位于 j 循环内。递归调用可能会删除国家的元素,这些元素也可能存在于首字母中。因此,您尝试多次删除它们,这会引发异常。您可能的意思是将chain(j) 放在循环之外(并且可能使用它的返回值?)

    【讨论】:

      【解决方案3】:

      附带说明,您的问题是 NP 完全的(这意味着它没有“快速”多项式时间解决方案。)它可以解决小问题,但很快就会变得非常困难。

      您的问题可以认为是longest-path problem on a directed graph

      • 绘制一个directed graph,将每个单词(国家)表示为一个顶点。
      • 对于每对单词w1w2,如果w1 的最后一个字母与w2 的第一个字母相同,则绘制一条边w1 -> w2
      • 如果w2s 的最后一个字母与w1s 的第一个字母相同,也从w2->w1 绘制反向边缘。
      • 找到maximum-length path - 包含最多顶点数的简单路径。 (在这种情况下,“简单”表示“不包含任何顶点不止一次。”)

      这是水果和蔬菜列表的示例图表:Apple, banana, eggplant, kiwifruit, orange, oregano, tangerine, zucchini

      这个图可能包含循环(例如,这个图有一个循环eggplant -> tangerine -> eggplant -> tangerine....The longest path problem for directed graphs containing cycles is NP-complete. 因此这个问题没有多项式时间解。

      这并不意味着你不能比蛮力做得更好。 There's a dynamic programming algorithm 将复杂性从 O(n!)(阶乘,非常不好)降低到 O(n^2 * 2^n)(超指数,仍然不好,但比阶乘好。)

      【讨论】:

        【解决方案4】:

        这是一种天真的递归方法……我觉得你可以使用动态编程,这样会更好

        def chain(start,options):
            #start is the starting word
            #options are the words left
        
            next_options = [country for country in options if country[0] == start[-1]]
        
            #if theres no options, return the single
            if not next_options:
                return [start]
        
            #otherwise, return best chain out of the next option
            best_chain = None
            longest_chain = 0
        
            for option in next_options:
        
                new_options = options[:]
                new_options.remove(option)
        
                possible_chain = chain(option,new_options)
        
                if len(possible_chain) > longest_chain:
                    best_chain = possible_chain
                    longest_chain = len(possible_chain)
        
            return [start] + best_chain
        

        【讨论】:

        • 动态编程可以帮助您将时间复杂度从O(n!)(阶乘)降低到更像O(n^2 * 2^n),这仍然很糟糕,但不太很糟糕。一般问题是 NP 完全的(见下文),这意味着不太可能存在“快速”算法。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-07-13
        • 1970-01-01
        • 2019-07-21
        • 2018-08-17
        • 2020-04-17
        • 2016-01-22
        相关资源
        最近更新 更多