Python:代码,用于查找前N个数字可被N整除的数字(从0到9)

时间:2015-07-20 03:38:47

标签: python algorithm recursion backtracking

我一直试图为程序编写一个递归解决方案,以找到一个前N个数字可被N整除的数字。

作为一个例子:3816547290,3可被1整除,38可被2整除,381可被3整除,依此类推......

我的递归解决方案正常运行"进入"递归,但在堆栈展开时有问题(即我没有特别知道如何回溯或采取措施

ARR = [0]*10
ARR[0] = 1 #dummy entry
def numSeq(pos, num):

    if all(ARR):
        print num
        return True

    if (pos>0) and (num%pos) != 0:
        return False

    for i in xrange(1,10):
        if ARR[i] == 1:
            continue
        new_num = num*10 + i
        if new_num%(pos+1) == 0:
            ARR[i] = 1
        numSeq(pos+1,new_num)

这段代码的问题似乎是它在进入递归时正确地跟随数字生成...所以它正确地生成了数字123654,它可以被6整除,并且前面的N个数字可以被N整除,但之后它没有找到7-8或9中除以7的任何其他数字,我没有得到下一组步骤来重置"全局ARR并从索引2开始,即尝试24xxxx,最终到达3816547290

先谢谢你的帮助!

编辑:我忘记提及的一个条件是每个数字必须只使用一次(即不允许重复数字)

第二次编辑

我能够最终应用适当的回溯来解决问题...此代码按原样运行。

ARR = [0]*10
def numDivisibile(num,pos):

    if all(ARR):
        print num
        return True

    for i in xrange(0,10):
        if ARR[i] == 1:
            continue
        new_num = num*10+i
        #check for valid case
        if new_num%(pos+1) == 0:
            ARR[i] = 1
            if numDivisibile(new_num, pos+1):
                return True
            #backtrack
            ARR[i] = 0

    return False

print numDivisibile(0, 0)

3 个答案:

答案 0 :(得分:3)

要生成所有10位数的整数,其中n的每个n数字可以n110包括#!/usr/bin/env python3 def generate_ints_nth_digit_divisible_by_n(n=1, number=0): number *= 10 if n == 10: yield number # divisible by 10 else: for digit in range(not number, 10): candidate = number + digit if candidate % n == 0: # divisible by n yield from generate_ints_nth_digit_divisible_by_n(n + 1, candidate) print("\n".join(map(str, generate_ints_nth_digit_divisible_by_n())))

1020005640
1020061620
1020068010
...
9876062430
9876069630
9876545640

输出

def divisibility_predicate(number):
    digits = str(number)
    for n in range(1, len(digits) + 1):
        if int(digits[:n]) % n != 0:
            return n - 1
    return n

def generate_digits_permutation(n=1, number=0, digits=frozenset(range(1, 10))):
    # precondition: number has n-1 digits
    assert len(set(str(number))) == (n - 1) or (number == 0 and n == 1)
    # and the divisibility condition holds for n-1
    assert divisibility_predicate(number) == (n - 1) or (number == 0 and n == 1)

    number *= 10
    if n == 10:
        assert not digits and divisibility_predicate(number) == 10
        yield number  # divisible by 10
    else:
        for digit in digits:
            candidate = number + digit
            if candidate % n == 0:  # divisible by n
                yield from generate_digits_permutation(n + 1, candidate, digits - {digit})


from string import digits
print([n for n in generate_ints_nth_digit_divisible_by_n()
       if set(str(n)) == set(digits)])
print(list(generate_digits_permutation()))

获取每个数字仅出现一次的数字,即找到满足可除性条件的数字的排列:

[3816547290]
[3816547290]

输出

{{1}}

答案 1 :(得分:1)

在你的函数中,你永远不会return numSeq(...),这似乎导致问题。

如果您想要一个迭代解决方案,可以查看以下内容:

def getN(number):
    strNum = str(number)
    for i in range(1, len(strNum)+1):
        if int(strNum[:i]) % i != 0:
            return i-1
    return i

print getN(3816)
print getN(3817)
print getN(38165)

<强>输出:

4
3
5

答案 2 :(得分:1)

我们可以稍微修改你的递归函数来尝试不同的可能性。而不是拥有已使用位置的全局记录(ARR),递归的每个线程将有自己的hash使用过的数字:

def numSeq(pos, num, hash):
  if pos != 1 and num % (pos - 1) != 0:   # number does not pass the test
    return

  elif pos == 11:                         # number passed all the tests
    print num

  elif pos == 5:
    numSeq(pos + 1,10 * num + 5,hash)     # digit is 5 at position 5

  elif pos == 10:
    numSeq(pos + 1,10 * num,hash)         # digit is 0 at position 10

  else:  
    k = 2 if pos % 2 == 0 else 1          # digit is even at even positions
    for i in xrange(k,10,2):
      if hash & (1 << i):                 # digit has already been used, skip it
        continue
      numSeq(pos + 1,10 * num + i,hash | (1 << i))

numSeq(1,0,0) # 3816547290