29
\$\begingroup\$

Repost and improvement of this challenge from 2011

A vampire number is a positive integer \$v\$ with an even number of digits that can be split into 2 smaller integers \$x, y\$ consisting of the digits of \$v\$ such that \$v = xy\$. For example:

$1260ドル = 21 \times 60$$

so \1260ドル\$ is a vampire number. Note that the digits for \$v\$ can be in any order, and must be repeated for repeated digits, when splitting into \$x\$ and \$y\$. \$x\$ and \$y\$ must have the same number of digits, and only one can have trailing zeros (so \153000ドル\$ is not a vampire number, despite \153000ドル = 300 \times 510\$).

You are to take a positive integer \$v\$ which has an even number of digits and output whether it is a vampire number or not. You can either output:

  • Two consistent, distinct values
  • A (not necessarily consistent) truthy value and a falsey value
    • For example, "a positive integer for true, 0 for false"

You may input and output in any convenient method. This is , so the shortest code in bytes wins.

The first 15 vampire numbers are \1260,ドル 1395, 1435, 1530, 1827, 2187, 6880, 102510, 104260, 105210, 105264, 105750, 108135, 110758, 115672\$. This is sequence A014575 on OEIS. Be sure to double check that your solution checks for trailing zeros; \153000ドル\$ should return false.

tsh
36.2k2 gold badges36 silver badges133 bronze badges
asked Feb 8, 2021 at 17:39
\$\endgroup\$
7
  • \$\begingroup\$ Sandbox. Brownie points for beating my 15 byte Jelly answer \$\endgroup\$ Commented Feb 8, 2021 at 17:39
  • 1
    \$\begingroup\$ does anyone else see something to the tune of ‘the first 15 vampire numbers are 1260 ... 102510 this 104620 ... 115672 is sequence’ etc.? \$\endgroup\$ Commented Feb 9, 2021 at 7:10
  • 1
    \$\begingroup\$ Just to be 100% sure: we don't have to check whether the input has an even number of digits, do we? \$\endgroup\$ Commented Feb 9, 2021 at 10:11
  • \$\begingroup\$ @Arnauld No, the input is guaranteed to have an even number of digits \$\endgroup\$ Commented Feb 9, 2021 at 12:44
  • \$\begingroup\$ I am writing a completely different solution, always in C. Would be acceptable to take as input n[]={1,2,6,0,1260}? Or is it too much? I am asking because I would need a for loop with two statements just to get 1260 from its digits (or the single digits from 1260) \$\endgroup\$ Commented Feb 9, 2021 at 15:51

15 Answers 15

7
\$\begingroup\$

Husk, (削除) 18 (削除ここまで) (削除) 17 (削除ここまで) (削除) 14 (削除ここまで) (削除) 13 (削除ここまで) 12 bytes

Edit: -3 bytes, and then another -1 byte, thanks to Leo, and -1 byte thanks to inspiration from pajonk's R answer (3rd edit)

1ドルmΠ†dm1⁄2f→Pd

Try it online!

Outputs nonzero integer if it's a vampire number, zero otherwise.

Commented penultimate version:

1ドル # index of input if present, zero otherwise, in
 mΠ # products of each element-pair
 †d # combining digits as a number from
 m1⁄2 # first & second halves of
 P # all permutations of
 d # digits of input;
 f # and filtering only element-pairs for which
 ṁ→ # sum of last digits is nonzero
answered Feb 8, 2021 at 22:39
\$\endgroup\$
4
  • \$\begingroup\$ Nice one! I believe the condition to your filter can be simplified to just ṁ→ (sum of the last element of each half) saving three bytes \$\endgroup\$ Commented Feb 8, 2021 at 23:59
  • \$\begingroup\$ And 1 more byte saved by using deep map ! tio.run/##ASUA2v9odXNr///igqzCuW3OoOKAoGRm4bmB4oaSbcK9UGT///… \$\endgroup\$ Commented Feb 9, 2021 at 0:03
  • 1
    \$\begingroup\$ @Leo - That's amazing! Thanks! I never really figured-out the difference between m and : this is the first time that I've seen them behave differently, so I'm still struggling to understand what's going on... (and why let's us avoid the o here...) \$\endgroup\$ Commented Feb 9, 2021 at 0:11
  • 1
    \$\begingroup\$ Come to the Husk chat if you want to talk about this :) \$\endgroup\$ Commented Feb 9, 2021 at 0:17
7
\$\begingroup\$

R, (削除) 156 (削除ここまで) (削除) 146 (削除ここまで) (削除) 143 (削除ここまで) (削除) 135 (削除ここまで) 145 bytes

-10 bytes thanks to Dominic van Essen.

+10 bytes fixing error pointed by DialFrost.

function(n,s=strsplit){for(i in 1:n)if(!n%%i&nchar(j<-n/i)==nchar(i)&all(sort(el(s(paste0(j,i),'')))==sort(el(s(c(n,''),''))))&j%%10)return(T)
F}

Try it online!

In newer R, 130 bytes

\(n,`+`=\(x)sort(el(strsplit(x,"")))){for(i in 1:n)if(!n%%i&nchar(j<-n/i)==nchar(i)&all(+paste0(j,i)==+c(n,''))&j%%10)return(T)
F}

Attempt This Online!

answered Feb 9, 2021 at 10:02
\$\endgroup\$
4
  • 2
    \$\begingroup\$ Really nice! And you can drop the 2xsort by using %in% for 146 bytes... \$\endgroup\$ Commented Feb 9, 2021 at 11:55
  • 2
    \$\begingroup\$ Edit 3 (only check %10 for one factor, since each pair will always occur both ways around) is really smart! I've copied the approach to save a byte in my Husk answer - Thanks! \$\endgroup\$ Commented Feb 11, 2021 at 8:08
  • \$\begingroup\$ Very late comment, but this appears to return T for many non-vampiric inputs, 1023, 1056, 1089 \$\endgroup\$ Commented Nov 9 at 1:18
  • \$\begingroup\$ @DialFrost thanks! Looks like the sorts were essential after all. \$\endgroup\$ Commented Nov 9 at 20:05
5
\$\begingroup\$

J, 43 bytes

".e.-@-:@#((0<[:".{:\)*[:*/".\)"1 i.@!@#A.]

Try it online!

Takes digits as a string.

For each permutation i.@!@#A.], use half the digit length -@-:@# to take non-overlapping infixes -- which slices into 2 halves -- and multiply those halves([:*/".\)"1. Then (to handle the trailing zero constraint) multiply that by (0<[:".{:\)*, which takes the last digits of each half, cats them, evaluates that as a two digit number, and checks if it's greater than 0.

Finally, check if the input number ". is an element of that list e..

answered Feb 8, 2021 at 20:40
\$\endgroup\$
4
  • \$\begingroup\$ I‘m not quite sure how the Footer works, how would I test this for a specific single input? \$\endgroup\$ Commented Feb 8, 2021 at 20:43
  • \$\begingroup\$ @cairdcoinheringaahing Edited TIO for clarity. \$\endgroup\$ Commented Feb 8, 2021 at 20:47
  • 1
    \$\begingroup\$ Looks like this fails for 153000 \$\endgroup\$ Commented Feb 8, 2021 at 21:08
  • 1
    \$\begingroup\$ Ugh, totally read over that the first time. Fixed now. Will regolf later. \$\endgroup\$ Commented Feb 8, 2021 at 21:42
5
\$\begingroup\$

JavaScript (Node.js), 88 bytes

f=(n,i=1)=>n<i*i*10&&i%10&&[...''+i+n/i].sort()+''==[...''+n].sort()||n*10>++i*i&&f(n,i)

Try it online!

  • [...''+i+n/i].sort()+''==[...''+n].sort() two factors use and only use digits in original number
    • if n/i is not an integer, it converted into a string with . and not equals to another side which doesn't contain a ..
  • n<i*i*10, n*10>i*i: lengths of two numbers are the same.
    • It equip to i/10 < n/i < i*10. And since n has even number of digits (as question mentioned), i and n/i will have same number of digits.
  • i%10: i is not end with "0"
answered Feb 9, 2021 at 8:32
\$\endgroup\$
1
  • \$\begingroup\$ -1 \$\endgroup\$ Commented Nov 11 at 5:40
4
\$\begingroup\$

05AB1E, 14 bytes

œ2δäÅΔPQy€θĀà*

Outputs a non-negative integer as truthy and -1 as falsey.

Try it online or verify all test cases.

Explanation:

œ # Get all permutations of the (implicit) input
 δ # Map over each permutation:
 2 ä # And split it into two equal-sized halves
 ÅΔ # Get the 0-based index of the first truthy result,
 # or -1 if none are found:
 P # Take the product of the two halves
 Q # And check that it's equal to the (implicit) input
 y # Push the halves again
 €θ # Only leave the last digit of each halve
 Ā # Check that it's not 0 (1 if [1-9]; 0 if 0)
 à # Get the maximum of these two
 * # Multiply the checks to verify both are truthy
 # (after which the found index is output implicitly as result)
answered Feb 9, 2021 at 8:09
\$\endgroup\$
0
4
\$\begingroup\$

Ruby, (削除) 104 (削除ここまで) 96 bytes

It almost looks like a complete English sentence. Which probably is a bad thing for golfing.

->n{n.digits.permutation.any?{|s|a,b=s.each_slice(s.size/2).map{|x|x.join.to_i};a%10>0&&a*b==n}}

Try it online!

It can be written in 94 bytes with Ruby 2.7:

->n{n.digits.permutation.any?{|s|a,b=s.each_slice(s.size/2).map{_1.join.to_i};a%10>0&&a*b==n}}
answered Feb 9, 2021 at 12:45
\$\endgroup\$
4
\$\begingroup\$

Python 2, (削除) 105 (削除ここまで) (削除) 95 (削除ここまで) 94 bytes

-10 bytes thanks to Kevin Cruijssen! (switch to Python 2)
-1 byte thanks to dingledooper!

Very inefficient, segfaults for \$ n \gtrsim 18500\$ on TIO.

f=lambda n,k=2,S=sorted:k<n and(k%10>n%k<(len(`k`)==len(`n/k`)<S(`k`+`n/k`)==S(`n`)))|f(n,k+1)

Try it online!

Commented:

f=lambda n,k=2,S=sorted # recursive function
 k<n # if k>=n return False
 and # otherwise:
 ( ... ) # long boolean expression which is True if k and n//k make n a valid vampire number
 k%10 # the last digit of k is 
 > n%k # larger than n%k which is
 < ( ... ) # less than another boolean expression
 # These two comparisons can only be satisfied with k%10>0<1
 len(`k`) # the number of digits of k
 == len(`n/k`) # is equal to the number of digits of n//k
 < S(`k`+`n/k`) # and sorting the digits of k and n//k 
 == S(`n`) # results in the same list as sorting the digits of n
| f(n,k+1) # bitwise OR with result of the recursive call
answered Feb 8, 2021 at 21:35
\$\endgroup\$
5
  • 1
    \$\begingroup\$ 97 bytes by switching to Python 2. \$\endgroup\$ Commented Feb 9, 2021 at 9:40
  • \$\begingroup\$ Reply to a deleted comment, but might be interesting to others: If n has divisors j and n//j that satisify all conditions, we will find this pair twice, since we iterate k from 2 to n. Either k=j or k=n//j satisfies k%10>0 and the remaining boolean expression is True for both values of k. \$\endgroup\$ Commented Feb 9, 2021 at 10:02
  • 1
    \$\begingroup\$ My comment above should be 95 bytes actually. The // can also be / in Python 2. \$\endgroup\$ Commented Feb 9, 2021 at 10:04
  • 1
    \$\begingroup\$ @KevinCruijssen thanks a lot! I was initially hesitant to use `n` here because this doesn't work for long integers, but I guess restricting this to int is fine. As a bonus Python 2 seems to run out of stack size a little bit later ;). \$\endgroup\$ Commented Feb 9, 2021 at 10:09
  • 1
    \$\begingroup\$ -1 byte since conditionals can be used on conflicting types in Python 2. \$\endgroup\$ Commented Feb 9, 2021 at 19:32
4
\$\begingroup\$

C (gcc), (削除) 286 (削除ここまで) (削除) 240 (削除ここまで) 218 bloody bytes (o,_,o)

-55 bloody bytes thanks to ceilingcat!

#define S(x,y)x^=y^=x^=y
o,a,b,c,r;f(int*_){c=atoi(_);v(o,_,o=strlen(_),r=0);r=r;}v(k,_,o,i)char*_;{--k?({for(v(k,_,o,0);i<k;v(k,_,o,!++i))S(_[k%2*i],_[k]);}):(a=atoi(_)/exp10(o/2))*(b=atoi(_+o/2))==c&&(a+b)%10?r=1:0;}

Try it online!

The input is a string and the output is either 1 or 0.

The core of the answer is the function v(), which implements Heap's algorithm to generate all the possible permutations of the input digits.

Here's an explanation of the code before some golfing:

#define S(x,y)x^=y^=x^=y // Macro used to swap digits
o, // length of the input string
a, // first half of one of the possible permutations of digits
b, // second half
r; // result: 1 if the input is a vampire number, 0 otherwise
char c[9]; // copy of the original input that will be compared with the permutations
f(_)char*_;{ // That's a simple function taking the input string
 r=!strcpy(c,_); // initializing `r` to 0 and `c` to the input
 v(o,_,o=strlen(_)); // calling v(o,_,o) while initializing `o` to the length of the input
 r=r; // and returning rhe result `r`
}
v( // v() is a recursive function taking three parameters:
k, // the length of a substring of digits being permuted
_, // the whole current permutation
o, // the length of the whole permutation
i) // `i` is here just to avoid declaring `int i` inside the `for` loop
char*_;{
 if(k-1){ // if `k` is not 1
 v(k-1,_,o); // call v() to permute `k-1` digits
 for(i=0;++i<k; // until `i` is less than `k`
 v(k-1,_,o)) // call v() to permute `k-1` digit, but only after having
 S(_[k%2?0:i-1],_[k-1]); // swapped _[k-1] with either _[0] or _[i-1]
 }
 else // else (i.e. if k == 1)
 (a=atoi(_)/exp10(o/2)) // if `a` (getting the first half of the permutation, converted to integer)
 *(b=atoi(_+o/2)) // multiplied by `b` (getting the second half)
 ==atoi(c) // equals the original input
 &&(a+b)%10? // and only one between `a` and `b` has trailing zeros
 r=1 // then the result is set to 1
 :0; // otherwise do nothing, this permutation wasn't the right one
}

I tried other algorithms, but couldn't find a shorter one. I leave here the dumbest of the tries, which is a solution that doesn't solve the problem. It only finds most of the vampire numbers (probably).

answered Feb 9, 2021 at 1:44
\$\endgroup\$
7
  • \$\begingroup\$ Looks like 15300 is included in your output list, when it should return false \$\endgroup\$ Commented Feb 9, 2021 at 2:00
  • \$\begingroup\$ @ceilingcat Wow thank you so much!! Using exp10 instead of pow made possible to cut off the (int) cast of the result. I own you these 5 more bytes. \$\endgroup\$ Commented Feb 9, 2021 at 11:39
  • 1
    \$\begingroup\$ You are right, the commas would indeed fix the issue because they are sequence points. However this is codegolf and undefined behaviors are well accepted as long as the program shows the expected output in at least one compiler of your choice. \$\endgroup\$ Commented Feb 9, 2021 at 21:19
  • 1
    \$\begingroup\$ @tgm1024--Monicawasmistreated if you wanted to swap without undefined behaviour the simplest solution is to just have an extra variable, z, and use z=x,x=y,y=z which adds 3 bytes (1 for longer macro and 2 for declaring z - since you cannot reuse an existing variable), compared to 4 for sequence points. but as noted UB is ok here. \$\endgroup\$ Commented Feb 11, 2021 at 9:44
  • 1
    \$\begingroup\$ Davide, @HansOlsson, understood. Still feeling my way around this site. \$\endgroup\$ Commented Feb 11, 2021 at 13:05
3
\$\begingroup\$

Charcoal, 54 bytes

⊞υ⟦ωθ⟧FυFE§ι1⟦+§ι0κΦ§ι1−λν⟧⊞υκ⊙EΦυ¬⊟ιI⪪⊟ι⊘Lθ∧Σ%ιχ=θIΠι

Try it online! Link is to verbose version of code. Outputs a Charcoal boolean, i.e. - for vampire, nothing if not. Explanation:

⊞υ⟦ωθ⟧

Start a breadth-first enumeration of permutations of the input string.

Loop over each partial permutation so far.

FE§ι1⟦+§ι0κΦ§ι1−λν⟧⊞υκ

Append each unused character to the permutation so far and push the result plus the remaining characters to the list.

⊙EΦυ¬⊟ι

Find whether any of the entries where all of the characters were used, ...

I⪪⊟ι⊘Lθ

... after being split into halves and cast to integer, ...

∧Σ%ιχ

... have a non-zero sum of the last digits, ...

=θIΠι

... and have the product of the halves resulting in the original string.

answered Feb 9, 2021 at 0:51
\$\endgroup\$
3
\$\begingroup\$

Python 2, (削除) 113 ... 112 (削除ここまで) 109 bytes

def f(n,s=sorted):x=s(`n`);l=10**(len(x)/2);return any(x==s(`i`+`n/i`)for i in range(l/10,l)if i%10and n%i<1)

Try it online!

-3 byte thanks Kevin Cruijssen

answered Feb 8, 2021 at 19:11
\$\endgroup\$
1
  • 1
    \$\begingroup\$ The // can be / for -3. It will do integer-division implicitly in Python 2 if both arguments are integers. (In Python 3+ you'll indeed have to use //.) \$\endgroup\$ Commented Feb 9, 2021 at 10:06
2
\$\begingroup\$

JavaScript (ES6), 93 bytes

Assumes that the input has an even number of digits. Returns a Boolean value.

f=(n,[...a]=n,p='')=>a[p.length]?a.some((v,i)=>f(n,a.filter(_=>i--),p+v)):p%10&&p*a.join``==n

Try it online!


JavaScript (ES6), 97 bytes

Expects the integer as a string. Returns 0 or 1.

f=(n,[...a]=n,p,q,k)=>a.some((v,i)=>f(n,a.filter(_=>i--),k?[p]+v:p,k?q:[q]+v,!k))|p%10*!(p*q^n|k)

Try it online!

Commented

f = ( // f is a recursive function taking:
 n, // n = input integer, as a string
 [...a] = n, // a[] = list of digits of n
 p, q, // n is split into p and q (both initially undefined)
 k // k is a flag, set on odd iterations
) => //
 a.some((v, i) => // for each digit v at position i in a[]:
 f( // do a recursive call:
 n, // pass n unchanged
 a.filter(_ => i--), // remove the i-th entry from a[]
 k ? [p] + v : p, // append v to p if k is set
 k ? q : [q] + v, // append v to q if k is not set
 !k // toggle k
 ) // end of recursive call
 ) // end of some()
 | // success if:
 p % 10 * // the last digit of p is not 0,
 !(p * q ^ n | k) // p * q = n and k is not set
answered Feb 8, 2021 at 20:05
\$\endgroup\$
2
\$\begingroup\$

Japt, 20 bytes

á mó f_dÌîmì ×ばつÃd\Uì

Try it online! or check all test cases (specifically the 15 vampire numbers and 153000)

Takes input as an array of digits. Input as an integer is one byte longer

Explanation:

á mó f_dÌîmì ×ばつÃd\Uì 
á # Get all permutations of the input digits
 mó # Divide each permutation into two groups of equal length
 f_ Ã # Only keep ones where:
 dÌ # At least one of the groups ends with a non-zero number
 ® Ã # For each remaining pair of groups:
 mì # Treat each group of digits as an integer
 ×ばつ # Multiply those integers
 d # Return true if at least one of the results...
 \Uì # ... Is equal to the original number
answered Mar 1, 2021 at 3:51
\$\endgroup\$
0
2
\$\begingroup\$

Japt -x, (削除) 14 (削除ここまで) 12 bytes

Takes input as (削除) a digit array (削除ここまで) an integer string. Outputs 0 for falsey or a positive integer for truthy.

á ËÌÑ©Dó ×ばつ\U

Try it

á ËÌÑ©Dó ×ばつ\U :Implicit input of integer string U
á :Permutations
 Ë :Map each D
 Ì : Last character
 Ñ : Multiplied by 2, to coerce to an integer (0 is falsey, everything else is truthy)
 © : Logical AND with
 Dó : Uninterleave D
 ×ばつ : Reduce by multiplication
 \U : Is loosely equal to U?
answered Nov 10 at 14:01
\$\endgroup\$
2
\$\begingroup\$

Nekomata -e, (削除) 11 (削除ここまで) (削除) 9 (削除ここまで) (削除) 15 (削除ここまで) (削除) 14 (削除ここまで) 12 bytes

ŝaƊpy,p{lZ}↕ɗ=

Attempt This Online!

-2 bytes thanks to alephalpha!

Explanation:

ŝaƊpy,ƆZɔ↕ɗ= | -e: Output whether a solution exists
-------------+-------------------------------------------------------
ŝ | Find two factors of input
 aƊ | Digits of both factors
 py | Are both lists the same length?
 , | Join lists
 ƆZɔ | Is the last digit non-zero?
 ↕ɗ= | Find a permutation that equals the digits of the input
answered Nov 9 at 21:47
\$\endgroup\$
6
  • \$\begingroup\$ Does this check that at least one partition doesn't end in 0? \$\endgroup\$ Commented Nov 10 at 21:12
  • \$\begingroup\$ @Shaggy it did not... I could have sworn that the false positive test case was accounted for, but apparently not. Fixed. \$\endgroup\$ Commented Nov 10 at 21:35
  • 1
    \$\begingroup\$ @Shaggy yes, I can! Thanks for the tip, I'll keep looking for more saves before I publish though \$\endgroup\$ Commented Nov 10 at 21:47
  • 1
    \$\begingroup\$ -2 bytes: p{lZ} -> ƆZɔ (\unsnoc \isNonzero \snoc). You can also use the -m flag to verify multiple test cases at the same time: Attempt This Online! \$\endgroup\$ Commented Nov 11 at 1:57
  • 1
    \$\begingroup\$ @alephalpha I knew I was missing something! Thank you, and I will have to remember the -m flag, that's really handy! \$\endgroup\$ Commented Nov 11 at 1:59
1
\$\begingroup\$

Jelly, 15 bytes

Œ!ŒH€SṪ$ƇḌP€=ḌẸ

Try it online!

Takes a list of digits.

answered Feb 8, 2021 at 22:53
\$\endgroup\$
2
  • 1
    \$\begingroup\$ 14 bytes (My solution, forgot I could input as digits) \$\endgroup\$ Commented Feb 8, 2021 at 23:25
  • 1
    \$\begingroup\$ @cairdcoinheringaahing Wow, it's exactly the same, except for the fact that I'm a moron and didn't realize that I could just use i. \$\endgroup\$ Commented Feb 8, 2021 at 23:28

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.