Pandigital Numbers
October 30, 2012
Numbers, or sets of numbers, that include all the digits only once are said to be pandigital. We test if a number or set of numbers is pandigital by looping all of the digits, keeping track in an array of all the digits seen so far. We return false if we see duplicates, or false if, after checking all the digits, there is one or more missing, or true otherwise. Digits are extracted by dividing by ten; the remainder is the right-most digit, and the quotient is the rest of the digits, shifted right one place.
(define (pandigital? . xs)
(let ((ds (make-vector 10 #f)))
(let x-loop ((xs xs))
(if (null? xs)
(let loop ((i 0))
(if (= i 10) #t
(if (not (vector-ref ds i)) #f
(loop (+ i 1)))))
(let d-loop ((x (car xs)))
(if (zero? x) (x-loop (cdr xs))
(let ((q (quotient x 10))
(r (remainder x 10)))
(if (vector-ref ds r) #f
(begin (vector-set! ds r #t)
(d-loop q))))))))))
With that, it is easy to answer the challenge question. We use nested loops to check each a, b, c triple in turn, reporting a result as soon as we find a pandigital number; this is guaranteed to be the smallest number because the loops run in increasing order, and a is always the smallest number in each triple:
> (let a-loop ((a 100))
(if (= a 1000) #f
(let b-loop ((b (+ a 1)))
(if (= b 1000) (a-loop (+ a 1))
(if (pandigital? a b (+ a b)) a
(b-loop (+ b 1))))))))
246
Collecting the complete list requires a small change to our loops; instead of stopping at the first triple, we collect all the triples in a list:
> (let a-loop ((a 100) (ps (list)))
(if (= a 1000) (reverse ps)
(let b-loop ((b (+ a 1)) (ps ps))
(if (= b 1000) (a-loop (+ a 1) ps)
(b-loop (+ b 1)
(if (pandigital? a b (+ a b))
(cons (list a b (+ a b)) ps)
ps))))))
((246 789 1035) (249 786 1035) (264 789 1053) (269 784 1053)
(284 769 1053) (286 749 1035) (289 746 1035) (289 764 1053)
(324 765 1089) (325 764 1089) (342 756 1098) (346 752 1098)
(347 859 1206) (349 857 1206) (352 746 1098) (356 742 1098)
(357 849 1206) (359 847 1206) (364 725 1089) (365 724 1089)
(423 675 1098) (425 673 1098) (426 879 1305) (429 876 1305)
(432 657 1089) (437 589 1026) (437 652 1089) (439 587 1026)
(452 637 1089) (457 632 1089) (473 589 1062) (473 625 1098)
(475 623 1098) (476 829 1305) (479 583 1062) (479 826 1305)
(483 579 1062) (487 539 1026) (489 537 1026) (489 573 1062)
(624 879 1503) (629 874 1503) (674 829 1503) (679 824 1503)
(743 859 1602) (749 853 1602) (753 849 1602) (759 843 1602))
You can run the program at http://programmingpraxis.codepad.org/38ciYhJc.
A Python solutions with loops:
[…] today’s Programming Praxis exercise, our goal is to find all possible combinations in which two 3-digit sum […]
My Haskell solution (see http://bonsaicode.wordpress.com/2012/10/30/programming-praxis-pandigital-numbers/ for a version with comments):
My Python solution. It enumerates the first 1m numbers to find all possible pairs of three-digit numbers. Then it filters them using sets to check pandigital-ness
http://pastebin.com/r3WqpAKM
[…] new post from Programming Praxis asked us to find all triples (a, b, a+b) such that a and b are three digits […]
Nice and straightforward and Racket’y: Pandigital sums
Also it definitely feels like another Project Euler problem. Which totally isn’t a problem except now it’s making me want to start working through those again. :)
Another Python solution. Simply iterate over all possible combinations of the numbers 0,1,..9. As the leading number of the sum is 1, 1 is not in the permutations, but is added at the end. In this way only pandigital number are generated and we only have to check if p1 < p2 and p1 + p2 = p3.
from itertools import permutations
for p in permutations([0,2,3,4,5,6,7,8,9]):
p = reduce(lambda a, b: 10 * a + b, p)
p , p3 = divmod(p, 1000)
p1, p2 = divmod(p, 1000)
if p1 < p2 and p1 + p2 == p3 + 1000:
print p1, p2, p3 + 1000
Repost. Something wrong with format?
Another Python solution. Simply iterate over all possible combinations of the numbers 0,1,..9. As the leading number of the sum is 1, 1 is not in the permutations, but is added at the end. In this way only pandigital number are generated and we only have to check if p1 < p2 and p1 + p2 = p3.
from itertools import permutations
for p in permutations([0,2,3,4,5,6,7,8,9]):
p = reduce(lambda a, b: 10 * a + b, p)
p , p3 = divmod(p, 1000)
p1, p2 = divmod(p, 1000)
if p1 < p2 and p1 + p2 == p3 + 1000:
print p1, p2, p3 + 1000
One in Prolog:
Hi! This is a very basic solution written in simple java- i’m 16 and still learning the basics.
How do you post it in the courier new font?
/*
* PAN-DIGITAL NUMBERS
* A 3-digit no plus another 3-digit no gives a 4-digit no.
* Find all such combinations of 3+3=4 in which all the 10 charcters used are different.
*/
class pandigital_nos
{
public void check()
{
int a, b, c, test_a, test_b, test_c, i, test_digit, test_nos_done, nos_done, c_len, count=0;
float digit, nos_digit;
boolean digits_valid=false, done_0=false;
//Make a for loop “firstno” to get the first number:
firstno:
for (a=100; a<=999; a++)
{
//Make a for loop "secondno" to get the second number:
secondno:
for (b=100; b=1)
{
c_len++;
test_c/=10;
}
//Reset the value of digits_valid:
digits_valid=true;
//Only if c is 4 digits let the rest happen:
if ((c_len)==4)
{
//Make test_a a to preserve a’s original value while testing it:
test_a=a;
//Make test_b b to preserve b’s original value while testing it:
test_b=b;
//Check a to see that all its digits are different:
//First check that the third digit is different from the first two:
//Make test_digit the last digit of a:
test_digit=a%10;
//Initialize the value of test_a as its first two digits:
test_a/=10;
for (i=1; i<=2; i++)
{
if (test_digit==test_a%10)
{
digits_valid=false;
//Change a by continuing with the first loop:
continue firstno;
}
test_a/=10;
}
//Second, check that the second digit is different from the first:
//Make test_digit the a's second digit:
test_digit=(a/10)%10;
if (test_digit==((a/100)%10))
{
digits_valid=false;
//Change a by continuing with the first loop:
continue firstno;
}
//Check b to see that all its digits are different:
//First check that the third digit is different from the first two:
//Make test_digit the last digit of b:
test_digit=b%10;
//Initialize the value of test_b as its first two digits:
test_b/=10;
for (i=1; i<=2; i++)
{
if (test_digit==test_b%10)
{
digits_valid=false;
//Change b by continuing with the "secondno" loop:
continue secondno;
}
test_b/=10;
}
//Second, check that the second digit is different from the first:
//Make test_digit the b's second digit:
test_digit=(b/10)%10;
if (test_digit==((b/100)%10))
{
digits_valid=false;
//Change b by continuing with the "secondno" loop:
continue secondno;
}
//Check c to see that all its digits are different:
//First, check that the fourth digit is different from the first three:
//Give test_c c's value again:
test_c=c;
//Make test_digit the last digit of c:
test_digit=c%10;
//Initialize the value of test_c as its first three digits:
test_c/=10;
for (i=1; i<=3; i++)
{
if (test_digit==test_c%10)
{
digits_valid=false;
//Change c by continuing with the "secondno" loop:
continue secondno;
}
test_c/=10;
}
//Second, check that the third digit is different from the first two:
//Make test_digit the third digit of c:
test_digit=(c/10)%10;
//Initialize the value of test_c as c's first two digits:
test_c=c/100;
for (i=1; i=1)
{
//Let digit become the last digit of test_b:
digit= test_b%10;
//Make test_nos_done nos_done to preserve b’s original value while testing it:
test_nos_done=nos_done;
//The for loop to perform the check:
while (test_nos_done>=1)
{
//Let nos_digit become the last digit of nos_done:
nos_digit=test_nos_done%10;
if (digit==nos_digit)
{
digits_valid=false;
//Change the numbers by continuing with the “secondno” loop:
continue secondno;
}
test_nos_done/=10;
}
test_b/=10;
}
//Give test_b b’s value again:
test_b=b;
//Add b’s digits to nos_done:
while (test_b>=1)
{
//Multiply the current nos_done by 10:
nos_done*=10;
//Add the last digit of test_b to nos_done:
nos_done+=test_b%10;
test_b/=10;
}
//Test c to see if its digits are different from a’s and b’s:
while (test_c>=1)
{
//Let digit become the last digit of test_c:
digit= test_c%10;
//Give test_nos_done nos_done’s value again:
test_nos_done=nos_done;
//The for loop to perform the check:
while (test_nos_done>=1)
{
//Let nos_digit become the last digit of nos_done:
nos_digit=test_nos_done%10;
if (digit==nos_digit)
{
digits_valid=false;
//Change the numbers by continuing with the “secondno” loop:
continue secondno;
}
test_nos_done/=10;
}
test_c/=10;
}
//Only if all the digits are unique print a, b and c:
if (digits_valid==true)
{
count++;
if (count==1)
{
System.out.println(“PAN-DIGITAL NUMBERS”);
System.out.println(“A 3-digit no plus another 3-digit no gives a 4-digit no.”);
System.out.println(“These are all such combinations of 3+3=4 in which all the 10 charcters used are different:”);
System.out.println(“”);
}
System.out.println(a+” + “+b+” = “+c);
}
}
}
}
}
}
[…] The Puzzle: A 3 digit number is added to another 3 digit number giving a sum. The sum is a 4 digit number. All the 10 digits are unique (0..9) consists of 7 distinct digits (from 0..9 ofcourse); Find the smallest such numbers. This puzzle comes from here. […]
My solution in FORTH; creates a bit mask to check for pandigitality. If the mask is 1023 at the end of the process then the number is pandigital. Uses integer log10 and 10^ words that I built into my FORTH image.
My C++ solution
#include
int main()
{
int r[3],l[3],a[4],k,m,n,t;
for(int i=100;i<=999;++i)
{
l[0]=i%10;
k=i/10;
l[1]=k%10;
l[2]=k/10;
if(l[0]!=l[1]&&l[1]!=l[2]&&l[2]!=l[0])
{
for(int j=100;j1000)
{
a[0]=n%10;
t=n/10;
a[1]=t%10;
t=t/10;
a[2]=t%10;
a[3]=t/10;
}
if(a[0]!=a[1]&&a[1]!=a[2]&&a[2]!=a[3]&&a[3]!=a[0]&&a[0]!=a[3]&&a[1]!=a[3]&&a[2]!=a[0]&&a[0]!=l[0]&&a[0]!=l[1]&&a[0]!=l[2]&&a[1]!=l[0]&&a[1]!=l[1]&&a[1]!=l[2]&&a[2]!=l[0]&&a[2]!=l[1]&&a[2]!=l[2]&&a[3]!=l[0]&&a[3]!=l[1]&&a[3]!=l[2]&&a[0]!=r[0]&&a[0]!=r[1]&&a[0]!=r[2]&&a[1]!=r[0]&&a[1]!=r[1]&&a[1]!=r[2]&&a[2]!=r[0]&&a[2]!=r[1]&&a[2]!=r[2]&&a[3]!=r[0]&&a[3]!=r[1]&&a[3]!=r[2])
{
printf(“%d %d %d \n”,i,j,n);
}
}
}
}
}
}
The brute force approach is above