优化Python函数以在Codewars上提交

时间:2017-09-22 07:09:45

标签: python optimization

我在this上有codewars.com问题的解决方案,当我在Sublime中运行时有效,但是当我尝试提交时,我收到此错误:

  

流程已终止。完成时间超过12000毫秒

     

为什么我的代码会超时?

     

我们的服务器配置为只允许一定的时间来执行代码。在极少数情况下,服务器可能会承担太多工作,而且根本无法有效地运行代码。大多数情况下,这个问题是由效率低下的算法引起的。如果您多次看到此错误,则应尝试进一步优化代码。

该功能的目标是通过重新排列给定数字的数字,找到您可以制作的给定数字后的下一个最大数字。例如,如果我被给予216,我将需要返回261.

这是我现在的代码:

import itertools

def next_bigger(n):

  # takes a number like 472 and puts it in a list like so: [4, 7, 2]
  num_arr = [int(x) for x in str(n)]
  perms = []
  total = ''

  # x would be a permutation of num_arr, like [7, 2, 4]
  for x in itertools.permutations(num_arr):
    for y in x:
      total += str(y)
    perms.append(int(total))
    total = ''

  # bigger is all permutations that are bigger than n, 
  # so bigger[0] is the next biggest number.
  # if there are no bigger permutations, the function returns -1

  bigger = sorted([x for x in perms if x > n])
  return bigger[0] if bigger else -1

我是Python新编码的新手,所以我制作的一些错误会导致我的代码效率极低吗?欢迎任何建议。

5 个答案:

答案 0 :(得分:2)

感谢你们给我的所有帮助。我最终使用下一个词典排列算法

here找到了一个解决方案

这是我提供的here解决方案的整理版本:

def next_bigger(n):
  # https://www.nayuki.io/res/next-lexicographical-permutation-algorithm/nextperm.py
  # https://www.nayuki.io/page/next-lexicographical-permutation-algorithm

  # Find non-increasing suffix
  arr = [int(x) for x in str(n)]
  i = len(arr) - 1
  while i > 0 and arr[i - 1] >= arr[i]:
    i -= 1
  if i <= 0:
    return -1

  # Find successor to pivot
  j = len(arr) - 1
  while arr[j] <= arr[i - 1]:
    j -= 1
  arr[i - 1], arr[j] = arr[j], arr[i - 1]

  # Reverse suffix
  arr[i : ] = arr[len(arr) - 1 : i - 1 : -1]
  return int(''.join(str(x) for x in arr))

答案 1 :(得分:1)

你为什么得到TLE (超出时限)?

因为您的算法具有错误的复杂性。使用 3 元素列出的列表会有多少排列?只有 6 。但是如果我们使用带有 23 元素的列表呢?的 25852016738884976640000 即可。 这太长了时间限制。

所以,如果你想解决这个问题,你必须找到没有排列的解决方案。请重新考虑如何编写数字。数字271大于216,因为第二位置上的数字具有更大的值7> 1。

因此,您的解决方案必须找到两个数字并交换位置。左边的数字必须小于第二个数字。

例如 - 对于111115444474444,您应该找到 5 7

然后你交换它们 - 现在你应该从第一个位置右侧对子列表进行排序。

例如,在交换了值(11111 7 4444 5 4444)后,您必须排序(444454444) - &gt; (444444445)。现在合并所有,你有解决方案。

import functools

def next_bigger(a):
    a = map(int, str(a))
    tmp = list(reversed(a))
    for i, item_a in enumerate(reversed(a)):

        for j in (range(i)):
            if item_a < tmp[j]:
                #you find index of number to swap
                tmp[i]=tmp[j]
                print(list(reversed(tmp[i:])))
                tmp[j]=item_a
                fin = list(reversed(tmp[i:])) + sorted(tmp[:i])

                return functools.reduce(lambda x,y: x*10+y, fin)
    return -1

答案 2 :(得分:0)

您应该按照desc顺序对num_arr进行排序,并通过组合结果来创建数字。

由于需要OP,下一个最大,OP需要从右边开始检查,哪个右边的数字大于它的左边数字并旋转它们的位置。

以下是最终代码:

def next_bigger(n):
    num_arr = [int(x) for x in str(n)]
    i = 0
    i = len(num_arr) - 1
    while(i > 0):
        if num_arr[i] > num_arr[i-1]:
            a = num_arr[i]
            num_arr[i] = num_arr[i-1]
            num_arr[i-1] = a
            break
        else:
            i = i-1
    newbig = "".join(str(e) for e in num_arr)
    return int(newbig)

答案 3 :(得分:0)

现在我编辑计算下一个更大的元素。

def perms(s):        
    if(len(s)==1): 
        return [s]
    result=[]
    for i,v in enumerate(s):
        result += [v+p for p in perms(s[:i]+s[i+1:])]
        return result

a=input()
b=perms(str(a))
if len(b)!=1:
    for i in range(0,len(b)):
        if b[i]==a:
            print (b[i+1])
            break
else:
    print ("-1")

答案 4 :(得分:0)

一种简单的回溯方法是一次考虑一个数字。从最重要的数字开始,选择您留下的最小数字,这不会阻止新数字超出输入。这将始终通过再现输入开始,然后将不得不回溯到倒数第二个数字(因为最后一个数字没有任何其他选择)。对于像897654321这样的输入,回溯将立即级联到开头,因为没有更大的数字可以在任何中间槽中尝试。