【问题标题】:Using permutations to find the next biggest number使用排列找到下一个最大的数字
【发布时间】:2020-11-18 03:48:58
【问题描述】:

创建一个函数,它接受一个正整数并返回下一个更大的数字,该数字可以通过重新排列其数字来形成。

为此,我使用了以下代码:

使用的逻辑:

  1. 编写一个脚本来完成数字的所有排列,例如123 -> 132,321,231,...
  2. 从可能的组合中选择最大的数
  3. 如果该数字大于原始数字,则返回该数字 - 如果不是,则返回 -1。

代码块:

import itertools
def next_bigger(n):
    # [int(x) for x in str(n)] ex: convert 123 to array [1,2,3]
    # list(set(itertools.permutations... gives you a list of permutation e.g. [[1,3,2],[3,2,1],[2,3,1],...]
    # [int(''.join(map(str,x))) for x in ...  converts each permuted list into a number e.g. convert [2,3,1] -> 231
    # for num in sorted(...if num>n: --> if 321 is bigger than 123, return it
    
     for num in sorted([int(''.join(map(str,x))) for x in list(set(itertools.permutations([int(x) for x in str(n)])))]):
        if num>n:
            return num
        else:
            return -1

预期输出:

nextBigger(num: 12)   // returns 21
nextBigger(num: 513)  // returns 531
nextBigger(num: 2017) // returns 2071
nextBigger(num: 9)   // returns nil
nextBigger(num: 111) // returns nil
nextBigger(num: 531) // returns nil

实际输出:Test results fail

解决方案尝试#2:

import itertools
def next_bigger(n):
    # [int(x) for x in str(n)] ex: convert 123 to array [1,2,3]
    # list(set(itertools.permutations... gives you a list of permutation e.g. [[1,3,2],[3,2,1],[2,3,1],...]
    # [int(''.join(map(str,x))) for x in ...  converts each permuted list into a number e.g. convert [2,3,1] -> 231
    # for num in sorted(...if num>n: --> if 321 is bigger than 123, return it
    
    a = []
    results = 0
    for num in sorted([int(''.join(map(str,x))) for x in list(set(itertools.permutations([int(x) for x in str(n)])))]):
        if num>n:
            a.append(num)
    results = a[0]
            
    return results

预期输出:通过除长数字以外的所有测试用例

我的代码有什么问题?

【问题讨论】:

  • 我们正在寻找下一个更大的排列,而不是最大排列。 (另外,遍历每一个排列非常慢。)
  • 那么最好的方法是什么?逻辑选择大于输入数字的数字
  • 有人应该对我进行理智检查,但似乎要使用的算法是取最低有效数字,将其与第一个较小的有效数字交换,然后对低于该数字的所有数字进行排序观点。因此,对于98176543,您将从3 开始,将其与1(左侧第一个较小的数字)交换以得到98376541,然后将所有数字排序到新3 位置的右侧,得到98314567 作为下一个更大的排列。就像我说的那样,这是第一个想法,而且已经晚了,所以我可能犯了一个基本的错误。如果它有效,它会比你的方法快得多。
  • 在检查时,它需要一些工作(如果最低有效位小于所有其他数字,则使用第二个最低有效位重试,依此类推)。

标签: python python-3.x permutation


【解决方案1】:

标题说“使用排列”,但您不需要为此使用排列。

定义了发出的元组itertools.permutations的顺序;但不幸的是,它并不总是产生组合时按递增顺序排列的数字。如果位数非常多,计算所有排列也需要很长时间。

换个说法:对于任何给定的N,最小的数字是多少(N2):

  1. 0 <= N < N2,和
  2. NN2中每个数字出现的次数相同

(如果N2不存在,则返回None

我们可以从N 开始,一直到N+=1 直到满足条件2,或者直到条件2 不再满足,因为N 的总位数增加了。 (Python 3 中的 int 没有定义它可以达到多大的限制,因此我们不会溢出。)如果 N 非常大,这仍然(平均而言)非常慢,但理论上它会最终回归。

我将如何解决这个问题:

def main(N):
    n=list(map(int,str(N)))
    for i_r in reversed(range(len(n))):
        for i_l in reversed(range(i_r)):
            if n[i_l]<n[i_r]:
                t_l=n[i_l]
                t_r=n[i_r]
                n[i_l]=t_r
                n[i_r]=t_l
                return int(''.join(map(str,n)))
    return None

首先将N 转换为数字列表(同时保留顺序)。这将使N 更易于处理。

制作 2 个标记 i_li_ri_li_r 将始终分别位于左侧和右侧。它们将从N 的最不重要(即右侧)开始。

他们会像这样通过N

4321    4321    4321    4321    4321    4321
  lr     l r    l  r     lr     l r     lr  

i_l &lt; i_r时,将这些数字交换成一个更大的数字,满足条件1。由于i_li_rN的最低有效侧开始,这个新数字是满足条件1的最小数字条件2. 如果该数字不存在,则函数返回None

return None 实际上是不必要的,因为函数默认返回 None,但明确说明它更清楚地表明这是预期的行为。)

使用此解决方案,即使N 是 10000 位,该函数也会在合理的时间内返回。

【讨论】:

    【解决方案2】:

    您需要下一个最大的数字,但目前您选择大于输入数字的any permutation-number。 You should be the picking the minimum among such numbers

    还要注意,例如对于输入9111;没有其他排列;所以你可能只想返回next biggest-permutation or None

    你可以考虑修改成这样:

    import itertools
    def next_bigger(n):
        # [int(x) for x in str(n)] ex: convert 123 to array [1,2,3]
        # list(set(itertools.permutations... gives you a list of permutation e.g. [[1,3,2],[3,2,1],[2,3,1],...]
        # [int(''.join(map(str,x))) for x in ...  converts each permuted list into a number e.g. convert [2,3,1] -> 231
        # for num in sorted(...if num>n: --> if 321 is bigger than 123, return it
        
         minval = -1
         for num in sorted([int(''.join(map(str,x))) for x in list(set(itertools.permutations([int(x) for x in str(n)])))]):
            if num>n:
                if minval == -1 or minval > num:
                    minval = n
         return minval
    

    适当的测试用例:

    nextBigger(num: 1176) //should return 1617
    

    【讨论】:

    • @ApplicationTeam 请详细说明
    • 您的代码没有清除任何测试用例,并且由于某种原因失败。但是,我得到了您尝试应用的逻辑,并提出了将数字附加到空列表的逻辑,只要它们大于输入的数字。完成后,我返回列表中第一个位置的值。测试用例通过,但在提交时,它只是继续执行
    • 它会在更大的数字上失败例如:492538761 492561378
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-18
    • 1970-01-01
    • 2019-09-10
    • 2018-06-27
    • 1970-01-01
    • 1970-01-01
    • 2015-09-27
    相关资源
    最近更新 更多