Longest chain of elements from list in Python

十年热恋 提交于 2019-12-04 06:54:28

I've also gone for recursive descent. Not sure if dynamic programming is a good fit for this as the list is modified as we go. Slightly more compact and doesn't need start removed from the list before calling chain. :-)

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

Call like this. :-)

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

Here are some comments:

  • you wish to return a path. So it is an ordered collection isn't it? You should probably not use a set for res, since set are unordered
  • do you know la length or the returned path? No you don't. So you might need a while somewhere
  • i.startswith(initial) is true only if i starts with the whole initial word. You probably don't want this
  • you try to use a recurcive approach. However you don't collect the result. The recurcive call is useless for the moment
  • nations is a global variable, which is bad

edit

The bug described in your comment may occur because your recurcive call is inside the j loop. The recurcive call may remove elements for the nations, which may also exist in initials. So you are trying to remove them more than once, which raises an exception. You probably mean to put chain(j) outside the loop (and maybe use its return value?)

Li-aung Yip

As a side note, your problem is NP-complete (meaning it has no "fast" polynomial-time solution.) It's solvable for small problem sizes, but it gets very difficult very quickly.

Your problem can be thought of as the longest-path problem on a directed graph.

  • Draw a directed graph with each word (country) represented as a vertex.
  • For every pair of words, w1 and w2, draw an edge w1 -> w2 if the last letter of w1 is the same as the first letter of w2.
  • Also draw the reverse edge from w2->w1 if w2s last letter is the same as w1s first letter.
  • Find the maximum-length path - the simple path containing the most number of vertices. ("simple" in this case means "not including any vertex more than once.")

Here's an example graph for a list of fruits and vegetables: Apple, banana, eggplant, kiwifruit, orange, oregano, tangerine, zucchini.

This graph may contain cycles (for example, this graph has a cycle eggplant -> tangerine -> eggplant -> tangerine..... The longest path problem for directed graphs containing cycles is NP-complete. Therefore there is no polynomial-time solution for this problem.

This doesn't mean you can't do better than brute force. There's a dynamic programming algorithm that reduces the complexity from O(n!) (factorial, very bad) to O(n^2 * 2^n) (superexponential, still bad, but better than factorial.)

this is a naive recursive approach... i feel like you could use dynamic programming and it would be better

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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!