数字列表中最长的蛇序列

时间:2015-06-09 14:14:09

标签: python arrays sequence

问题:以空格分隔的一组数字作为输入传递。程序必须打印数字中存在的最大蛇序列。蛇序列由相邻的数字组成,因此对于每个数字,右侧或左侧的数字是它的值的+1或-1。如果可能存在多个最大长度的蛇序列,则打印出以自然输入顺序出现的蛇序列。

示例输入/输出1:

输入:

9 8 7 5 3 0 1 -2 -3 1 2

输出:

3 2 1 0 1

示例输入/输出2:

输入:

-5 -4 -3 -1 0 1 4 6 5 4 3 4 3 2 1 0 2 -3 9

输出:

6 5 4 3 4 3 2 1 0 -1 0 1 2

示例输入/输出3:

输入:

5 6 7 9 8 8

输出:

5 6 7 8 9 8

我从这个链接找到了一个Python程序: "Longest Snake in an array" 如下所示,但未能满足以下测试用例。如在问题中提到的,在两个或更多个最大长度序列的情况下,程序必须打印出现在自然输入顺序中的蛇序列。我怀疑这是造成问题的参数。

输出应该是这个程序显示的内容,因为差异点是8和10.(如果我对自然顺序的含义没有错)8在输入列表中出现在10之前应该进入正确的顺序输出而不是10,但这不是预期的输出。

"""
Test case Input:
4 3 1 6 7 8 8 21 7 8 9 13 -1 2 14 9 10 11 10 9

Expected Output:
6 7 8 7 8 9 10 11 10 9 8 9

Your Program Output:
6 7 8 7 8 9 8 9 10 9 10 11
"""

from collections import Counter
def longest_snake(numbers,counts,path):
        best = path
        for n in sorted(counts, key = numbers.index, reverse=True):
                if counts[n] > 0 and (path == [] or abs(path[-1] - n) == 1):
                        counts[n] -= 1
                        res = longest_snake(numbers,counts,path + [n])
                        if (len(res) > len(best)):
                                best = res
                        counts[n] += 1
        return best
if __name__ == '__main__':
        numbers = list(map(int, raw_input().split()))
        output = longest_snake(numbers,Counter(numbers),[])[::-1]
        print(' '.join(map(str,output)))

1 个答案:

答案 0 :(得分:0)

我的算法略有不同。它仍然不能满足所有测试用例,但它更接近我所理解的“自然输入顺序”。

def longest_snake(numbers, counts, path, pos=0):
    visited = set()                                # keep track of visited nodes
    best, total = path, pos                        # best path and best pos
    for i in range(len(numbers)):                  # for one more round...
        n = numbers[(pos + i) % len(numbers)]      # wrap around edges, get n
        if n not in visited and counts[n] > 0 and (path == [] or abs(path[-1] - n) == 1):
            visited.add(n)
            counts[n] -= 1
            res, t = longest_snake(numbers, counts, path + [n], pos + i)
            if len(res) > len(best) or (len(res) == len(best) and t < total):
                best, total = res, t               # longer path or fewer steps
            counts[n] += 1
    return best, total                             # return both path and total steps

以下是它现在的工作原理:

  • 它会跟踪输入列表中的当前位置(pos
  • 在递归时,它继续在该位置,将pos + i传递给递归调用,从而首先尝试“数据块”
  • 如果pos + i大于输入的长度,则会将其包裹到开头
  • 如果两条蛇道具有相同的长度,则需要具有较低总位置的路径,即输入较少进展且较少“开始”到开头是必要的

正如我所说,它更接近“自然输入顺序”,但仍然不完美。这是一个例子:

6 5 4 3 4 3 2 1 0 -1 0 1 2  # expected output
4 5 4 3 4 3 2 1 0 -1 0 1 2  # my output 

最后,归结为如何定义“自然输入顺序”。采用第一个测试用例,即9 8 7 5 3 0 1 -2 -3 1 2:此版本的代码产生1 0 1 2 3,但预期为3 2 1 0 1。但为什么?我的结果有一对数字在输入(1 2)中彼此相邻,而预期的输出没有,我的也有更少的“步数”(两次左右,然后到{{1}虽然预期有两次,但最多有一次3 s。。

或者换句话说:您可以使用我的算法并将条件更改为:

1

如果您可以定义函数if len(res) > len(best) or (len(res) == len(best) and isMoreOrdered(numbers, res, best)):` ,那么您就完成了。但是从几个例子和问题的措辞来看,我当然无法分辨。

无论如何,也许这给了你一些想法,你可以自己找出其余的。