简体   繁体   中英

Find all three “two digit numbers” with no repeated digit

Write a program that finds all triples of positive integers (i, j, k) such that i , j and k are two digit numbers, no digit occurs more than once in i , j and k .

And I wrote:

for i in range(10,100):
    for j in range(10,100):
        for k in range(10,100):
                if i%10 !=i//10 !=j%10 !=j//10 != k%10 != k//10:
                    print(i,j,k)

Why is it still incorrect? It still contains the same digit in i , j , k . What's wrong?

As Arya McCarthy mentioned, your code only checks that they're not all the same. The code below checks if there are no duplicate digits present in i , j , or k .

for i in range(10,100):
    for j in range(10,100):
        for k in range(10,100):
            digits = {i%10, i//10, j%10, j//10, k%10, k//10}
            if len(digits) == 6:
                print(i,j,k)

You can build a set from the two digit numbers directly and check the length is 6; save all the math:

for i in range(10,100):
    for j in range(10,100):
        for k in range(10,100):
            if len(set('{}{}{}'.format(i,j,k))) == 6:
                    print(i,j,k)

If you choose to stick with the math, you can replace % and // with divmod and then check:

len(set(divmod(i,10)+divmod(j,10)+divmod(k,10))) == 6

Another way to do this, using itertools.combinations :

from itertools import combinations

possible_values = combinations(range(10, 100), 3)

satisfies_condition = {(x, y, z) for x, y, z in possible_values if 
                        len({x%10, x//10, y%10, y//10, z%10, z//10}) == 6}

print('\n'.join(map(str, satisfies_condition)))

Prints:

(17, 40, 82)
(74, 90, 28)
(29, 37, 40)
(73, 96, 10)
(31, 97, 85)
(83, 70, 91)
(15, 23, 69)
(23, 49, 15)
(56, 18, 37)

Technically, to match what you're doing, you'd use itertools.permutations (since order matters in your approach). But I think, at this problem's core, combinations of length three are most appropriate.

There's a faster approach to solve the question; using combinations and permutations :

from itertools import combinations, permutations

l = range(10)

for c in combinations(l, 6):  # all 6-combinations of the numbers 0-9
    for c1, c2, c3, c4, c5, c6 in permutations(c):  # all permutations of these numbers
        if c1 == 0 or c3 == 0 or c5 == 0:
            continue  # exclude those where the first digit of any number is 0
        else:
            print('{}{} {}{} {}{}'.format(c1, c2, c3, c4, c5, c6))

This takes 6 numbers from the numbers 0 to 9 (without replacement!) and then iterates over all permutations of these. The only check is that the first digit of each number isn't 0 (otherwise it wouldn't be a two-digit number according to the problem). To get the numbers you could use:

i = 10*c1 + c2
j = 10*c3 + c4
k = 10*c5 + c6

If you need them.

Using that approach you don't need to throw away that many numbers compared to your original approach.

You could even go a step further and use a set from which to draw the numbers:

l = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}  # set of allowed numbers

for n1 in l - {0}:  # all numbers except 0
    for n2 in l - {n1}:  # all numbers except the first number
        for n3 in l - {0, n1, n2}:  # all numbers except 0 and the first and second number
            for n4 in l - {n1, n2, n3}:  # ...
                for n5 in l - {0, n1, n2, n3, n4}:
                    for n6 in l - {n1, n2, n3, n4, n5}:
                        print('{}{} {}{} {}{}'.format(n1, n2, n3, n4, n5, n6))

That replaces the if conditions with set differences and generates no "unnecessary" pairs.

Timing

To see what a difference the approach can make I timed the different answers:

%%timeit

l = set(range(10))

for n1 in l - {0}:
    for n2 in l - {n1}:
        for n3 in l - {0, n1, n2}:
            for n4 in l - {n1, n2, n3}:
                for n5 in l - {0, n1, n2, n3, n4}:
                    for n6 in l - {0, n1, n2, n3, n4, n5}:
                        pass

57.3 ms ± 295 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

%%timeit

from itertools import combinations, permutations

l = range(10)

for c in combinations(l, 6):
    for c1, c2, c3, c4, c5, c6 in permutations(c):
        if c1 == 0 or c3 == 0 or c5 == 0:
            continue
        else:
            pass

61.2 ms ± 101 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

%%timeit

for i in range(10,100):
    for j in range(10,100):
        for k in range(10,100):
            digits = {i%10, i//10, j%10, j//10, k%10, k//10}
            if len(digits) == 6:
                pass

1.7 s ± 2.36 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%%timeit

for i in range(10,100):
    for j in range(10,100):
        for k in range(10,100):
            if len(set('{}{}{}'.format(i,j,k))) == 6:
                pass

3.29 s ± 40.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%%timeit

from itertools import combinations

possible_values = combinations(range(10, 100), 3)

satisfies_condition = {(x, y, z) for x, y, z in possible_values if 
                        len({x%10, x//10, y%10, y//10, z%10, z//10}) == 6}

for i in satisfies_condition:
    pass

300 ms ± 7.73 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

So the approaches that generate less to-be-excluded pairs (the first two) are ~5 times faster than an approach using a C-loop (the combinations approach given by @not_a_robot - however that approach doesn't give all solutions so in practice it will be a lot slower) and ~30 times faster than the three loops over the range(10, 100) (the answer of @Will Da Silva - the answer by @Moses Koledoye is even slower because string formatting or tuple concatenation is a lot slower than using a set literal).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM