[InterviewBit]Power Of Two Integers - algorithm

this is the question:
Given a positive integer which fits in a 32 bit signed integer, find if it can be expressed as A^P where P > 1 and A > 0. A and P both should be integers.
I know that I can solve it using brute-force method; however, I am wondering if I could solve it in a better way, or can I solve it using recursion technique?
Thanks for your kind help!

One approach is to convert to double, and use math to obtain fractional powers of 1/2, 1/3, 1/4, and so on, up to 1/log2 n. The result would be an A; the denominator of the fraction would be P.
Since the computation of the power is in doubles, you would need to try both ceil and floor of the result. Once you hit zero without finding a result, the algorithm could stop.

This can also be solved this way.
public boolean isPower(int a) {
if (a == 1) return true;
for (int idx = 2; idx * idx <= a; idx ++) {
double val = Math.log (a)/Math.log (idx);
if ((val - (int) val) < 0.00000001) return true;
}
return false;
}

we will check if a == 1 then it can be represented as x ^ 0 hence
true . for a > 1 we will check for either 2 or 3 or 4....a; we will
divide p (p = a) if p % 2 or ,3 or ,4 or ....... if(p==1) means p is
completely divisible by either 2, or 3, or 4 , ...... . means p
(where p = a) can we written as x ^ y. hence return true.
public boolean isPower(int a) {
if(a==1) return true;
for (int i = 2; i*i <= a; i++) {
int p = a;
while(p%i == 0){
p/=i;
}
if(p == 1) return true;
}
return false;
}

Code based on #xenteros Answer and a successful submission .
public static int isPower(int A) {
if(A == 1)
return 1;
double Ad = A ;
for(int i =2;i<=(Math.log(Ad)/Math.log(2));i++)
{
double a = Math.pow(Ad,(double)1/i);
if(Math.ceil(a) == Math.floor(a) || Math.ceil(a)-a <0.000000001)
return 1;
}
return 0;
}

while(test--)
{
int input;
cin>>input;
if(input<=2)
{cout<<"0"<<endl;
break;}
//cout<<m;
int m=sqrt(input);
int count=2;
int flag=0;
while(count<=m+1)
{
if(ceil(log2 (input)/log2 (count))== floor(log2 (input)/log2 (count)))
{
// cout<<"ghusa "<<count<<" "<<input;
flag=1;
cout<<"1";
break;
}
count++;
}
if(flag==0)
{cout<<"0";
}
cout<<endl;
}
return 0;
}

bool ans(long long int n)
{
if(n==1)
return true;
else
{
for (long long int i = 2; i*i <= n; i++)
{
if(ceil(log2 (n)/log2 (i)) == floor(log2 (n)/log2 (i)))
{
return true;
}
}
}
return false;
}

Lets call the initial integer N.
First, you must get all the prime divisors of N.
If N has just 1 divisor, that it is in the form D^k, so it's true.
If it has more than 1 divisor, you should check if the gcd of the number of each divisor is different from 1 and is even.
For example:
12 = 2 * 2 * 3
not possible, GCD(2,1) = 1
24 = 2 * 2 * 2 * 3
not possible, GCD(3,1) = 1
36 = 2 * 2 * 3 * 3
possible, GCD(2,2) = 2
144 = 2 * 2 * 2 * 2 * 3 * 3
possible, GCD(4,2) = 2
120 = 2 * 2 * 2 * 3 * 5
not possible, GCD(1,1,3) = 1
216 = 2 * 2 * 2 * 3 * 3 * 3
not possible, GCD(3,3) = 3

Related

How to find the optimal strategy in this scenario?

The scenario looks something like this:
Given an array of 1's and 2's, we want to make it all ones. There are following constraints:
In every step, one of the 2's could exchange its position with the adjacent one.
1 2 1 2 1
could be transformed to:
2 1 1 2 1
in single step.
If a 2 appears at the edge, it could be broken down into 2 ones in a single step.
2 1 2 1
1 1 1 2 1
in single step
If two twos are adjacent they could be broken down into ones.
1 2 2 1
into
1 *1 1 1 1* 1
it costs us 2 steps.
So the problem is, given n steps can we make it all one?
I don't want the complete answers some small insight would also do.
Here is a constructive solution.
Lemma: It's never optimal to broke more than one 2 near the border (both left and right).
Proof: Assume in optimal solution we've broken the two leftmost 2s near the left border and their positions in array were x and y (x <= y). We used x + y + 2 operations to brake them up. But if we just move them in adjacent tiles and perform 3rd type of operation, we achieve only y - x + 1 operations. So previous solution wasn't optimal. Proved.
So there is just 4 cases:
Don't use 2nd operation at all (only if number of 2 is even).
Use 2nd operation only at left border (only if number of 2 is odd).
Use 2nd operation only at right border (only if number of 2 is odd).
Use 2nd operation at both borders (only if number of 2 is even).
After upper process we have even number of 2. So just pair them and brake via 3rd operation.
The complexity of solution is O(n), since we have O(n) input data it's the most optimal way to deal this problem.
Feel free to ask questions or code.
I tried to develop dynamic programming algorithm but could not find the optimal substructure.
This is the brute force, most time consuming, recursive solution.
We have to find whether we can reduce input to all 1's.
Input array has 1's and 2's and there are rules to convert 2's into 1's.
The naive approach is to apply the rule wherever possible and try to find out whether the output can be achieved
The pseudo-code-ey algorithm is :
boolean check(int[] input, int steps) {
if(steps == 0) {
return allOnes(input)
}
step--
boolean ans = false;
if(input[0] == 2) {
breakEdgeTwoIntoOne(input,0) // function for rule 2
revert(input) // convert input to original
ans = ans | check(input,steps)
}
if(input[input.length-1] == 2) {
breakEdgeTwoIntoOne(input,input.length - 1)
revert(input)
ans = ans | check(input,steps)
}
for(i=0;i<input.length-1;i++) {
if(input[i] == 2 && input[i+1] == 2) {
breakTowAdjecentTwosIntoOnes(input,i) // function for rule 3
revert(input)
ans = ans | check(input,steps)
}
}
for(i=0;i<input.length-1;i++) {
if( input[i] == 2 ) {
swapLeft(input, i) // function for rule 1
ans = ans | check(input,steps)
revert(input)
swapRight(input, i)
ans = ans | check(input,steps)
revert(input)
}
}
return ans;
}
The not-so-elegnet java implementation for all the functions :
static boolean check(int[] input, int steps) {
if (allOnes(input)) {
return true;
}
if (steps == 0) {
return allOnes(input);
}
steps--;
int original[] = new int[input.length];
System.arraycopy(input, 0, original, 0, input.length);
boolean ans = false;
if (input[0] == 2) {
ans = ans | check(breakEdgeTwoIntoOne(input, 0), steps);
System.arraycopy(original, 0, input, 0, input.length);
}
if (input[input.length - 1] == 2) {
ans = ans | check(breakEdgeTwoIntoOne(input, input.length - 1), steps);
System.arraycopy(original, 0, input, 0, input.length);
}
for (int i = 0; i < input.length - 1; i++) {
if (input[i] == 2 && input[i + 1] == 2) {
ans = ans | check(breakTowAdjecentTwosIntoOnes(input, i), steps);
System.arraycopy(original, 0, input, 0, input.length);
}
}
for (int i = 0; i < input.length - 1; i++) {
if (input[i] == 2) {
if (i != 0) {
ans = ans | check(swapTwoToLeft(input, i), steps);
System.arraycopy(original, 0, input, 0, input.length);
}
if (i != input.length - 1) {
ans = ans | check(swapTwoToRight(input, i), steps);
System.arraycopy(original, 0, input, 0, input.length);
}
}
}
return ans;
}
private static int[] breakTowAdjecentTwosIntoOnes(int[] input, int i) {
int op[] = new int[input.length + 2];
int k = 0;
for (int j = 0; j < input.length; j++) {
if (j == i || j == i + 1) {
op[k++] = 1;
op[k++] = 1;
// j++;
} else {
op[k++] = input[j];
}
}
return op;
}
private static int[] breakEdgeTwoIntoOne(int[] input, int i) {
int op[] = new int[input.length + 1];
if (i == 0) {
op[0] = 1;
op[1] = 1;
System.arraycopy(input, 1, op, 2, input.length - 1);
} else {
op[op.length - 2] = 1;
op[op.length - 1] = 1;
System.arraycopy(input, 0, op, 0, input.length - 1);
}
return op;
}
private static int[] swapTwoToRight(int[] input, int i) {
if (i != input.length - 1) {
int k = input[i + 1];
input[i + 1] = input[i];
input[i] = k;
}
return input;
}
private static int[] swapTwoToLeft(int[] input, int i) {
if (i != 0) {
int k = input[i - 1];
input[i - 1] = input[i];
input[i] = k;
}
return input;
}
private static boolean allOnes(int[] input) {
for (int x : input) {
if (x != 1)
return false;
}
return true;
}
Some of test cases
[1,2,1,2,1],1 => false
[1,2,1,2,1],2 => true
[1,2,1,2,1],3 => true
[2,2,2],1 => false
[2,2,2],2 => true
[2,2,2],3 => true
[2,2,2],4 => true

Divide a large number represented in string by 2 , add 1 or substract 1 [duplicate]

This question already has answers here:
minimum number of steps to reduce number to 1
(10 answers)
Closed 6 years ago.
I am working on a code challenge now. My solution got "time exceed" even I have optimized it. I am seeking for help about more efficient solution or optimizing my solution a step more.
The description of the problem is :
Write a function which takes a positive integer as a string and returns the minimum number of operations needed to transform the number to 1. The number is up to 309 digits long, so there won't too many character than you can express in that many digits.
The transform process is limited to three operations:
1. Add 1
2. Subtract 1
3. Divide the number by 2 (only even number allow here)
My idea is to use DFS to traverse all possible solution with memorization to speed it up. But it does exceed the time limitation. The problem can not use dp because dp require a very large array to memorize. Below is my code:
private static int dfs(String num, int step,Map<String,Integer> memory){
if(num.equals("1")){
return step;
}
Integer size = memory.get(num);
if(size != null && size < step){
return Integer.MAX_VALUE;
}
memory.put(num, step);
int min = Integer.MAX_VALUE;
int lastDigit = num.charAt(num.length() - 1) - '0';
if(lastDigit % 2 == 0){
min = Math.min(min, dfs(divideBy2(num), step + 1, memory));
}else{
min = Math.min(min, dfs(divideBy2(num), step + 2, memory));
min = Math.min(min, dfs(divideBy2(plusOne(num)), step + 2, memory));
}
return min;
}
private static String plusOne(String num){
StringBuilder sb = new StringBuilder();
int carry = 1;
for(int i = num.length() - 1; i >=0; i--){
int d = (carry + num.charAt(i) - '0') % 10;
carry = (carry + num.charAt(i) - '0') / 10;
sb.insert(0, d);
}
if(carry == 1){
sb.insert(0, carry);
}
return sb.toString();
}
private static String divideBy2(String num){
StringBuilder sb = new StringBuilder();
int x = 0;
for(int i = 0; i < num.length(); i++){
int d = (x * 10 + num.charAt(i) - '0') / 2 ;
x = (num.charAt(i) - '0') % 2 ;
if( i > 0 || (i == 0 && d != 0))
sb.append(d);
}
return sb.toString();
}
Note: After test several cases: I got some sense but can not generalize the rule.
If the current number is odd. we got two choices here: plus 1 or subtract 1. The number after the operation can be divided by 2 more times, the steps will be shorter.
Update: Hi, guys, I work all the night and find a solution to pass the test. The idea is divide the problem into 2 sub-problem: 1. if the number is even, just divide it by two. 2. if the number is odd, choose the way let the number has more tailing zeros in its bit representation. I will explain more about the odd situation: if the number is odd, the last two bit can be "01" or "11". When it is "01", decrease it by 1 , which let the last two bit become to "00". If it is "11", increase it by 1, which generate "00". By doing this, the next even number generated by the odd number can be divided more times, which is really fast in practice. Below is my code, if you have some questions about the implementation, feel free to send me a message:
public static int answer(String n) {
// Your code goes here.
int count = 0;
while(!n.equals("1")){
if((n.charAt(n.length() - 1) - '0') % 2 == 0){
n = divideBy2(n);
}else if(n.equals("3") || lastTwoBit(n)){
n = subtractOne(n);
}else{
n = plusOne(n);
}
count++;
}
return count;
}
private static boolean lastTwoBit(String num){
int n = -1;
if(num.length() == 1){
n = Integer.valueOf(num);
}else{
n = Integer.valueOf(num.substring(num.length() - 2, num.length()));
}
if(((n >>> 1) & 1) == 0){
return true;
}
return false;
}
private static String subtractOne(String num){
if(num.equals("1")){
return "0";
}
StringBuilder sb = new StringBuilder();
int carry = -1;
for(int i = num.length() - 1; i >= 0; i--){
int d = carry + num.charAt(i) - '0';
if(d < 0){
carry = -1;
sb.insert(0, '9');
}else if((d == 0 && i != 0) || d > 0){
carry = 0;
sb.insert(0, d );
}
}
return sb.toString();
}
private static String plusOne(String num){
StringBuilder sb = new StringBuilder();
int carry = 1;
int i = 0;
for(i = num.length() - 1; i >=0; i--){
if(carry == 0){
break;
}
int d = (carry + num.charAt(i) - '0') % 10;
carry = (carry + num.charAt(i) - '0') / 10;
sb.insert(0, d);
}
if(carry ==0){
sb.insert(0, num.substring(0, i + 1));
}
if(carry == 1){
sb.insert(0, carry);
}
return sb.toString();
}
private static String divideBy2(String num){
StringBuilder sb = new StringBuilder();
int x = 0;
for(int i = 0; i < num.length(); i++){
int d = (x * 10 + num.charAt(i) - '0') / 2 ;
x = (num.charAt(i) - '0') % 2 ;
if( i > 0 || (i == 0 && d != 0))
sb.append(d);
}
return sb.toString();
}
While not at 1...
if Odd... Subtract 1 => even
if Even.. Divide by 2.
just sum the ops and return.
e.g. 5593
5593 -1 = 5592 /2 = 2796 /2 = 1398 /2 = 699 -1 = 698 /2 = 349 -1 = 348 /2 = 174 /2 = 87 -1 = 86 /2 = 43 -1 = 42 /2 = 21 -1 = 20 /2 = 10 /2 = 5 -1 = 4 /2 = 2 /2 = 1
19 Operations -///-/-//-/-/-//-//
Edit: Time complexity is O(logN) for we divide the number by two / subtract and then divide.
and Space is O(1)
public int make1(string s)
{
int n = 0;
while(s != "1")
{
switch(s[s.Length-1])
{
case '0':
case '2':
case '4':
case '6':
case '8':
s = div2(s);
++n;
break;
case '1':
case '3':
case '5':
case '7':
case '9':
s = minus1(s);
s = div2(s);
n += 2;
}
}
return n;
}

Solve number of substrings having two unique characters in O(n)

I'm working on a series of substring problem:
Given a string:
Find the substring containing only two unique characters that has maximum length.
Find the number of all substrings containing AT MOST two unique characters.
Find the number of all substrings containing two unique characters.
Seems like problem 1 and 2 has O(n) solution. However I cannot think of a O(n) solution for problem 3.(Here is the solution for problem 2 and here is for problem 1.).
So I would like to know does a O(n) solution for problem 3 exist or not?
Adding sample input/output for problem 3:
Given: abbac
Return: 6
Because there are 6 substring containing two unique chars:
ab,abb,abba,bba,ba,ac
Find the number of all substrings containing two unique characters.
Edit : I misread the question. This solution finds unique substrings with at least 2 unique characters
The number of substrings for a given word whose length is len is given by len * (len + 1) / 2
sum = len * (len + 1) / 2
We are looking for substrings whose length is greater than 1. The above formula includes substrings which are of length 1. We need to substract those substrings.
So the total number of 2 letter substrings now is len * (len + 1) / 2 - l.
sum = `len * (len + 1) / 2 - l`
Find the longest consecutive run of characters which are alike. Apply step 1 and 2.
Subtract this current sum from the sum as obtained from step 2.
Sample implementation follows.
public static int allUniq2Substrings(char s[]) {
int sum = s.length * (s.length + 1) / 2 - s.length;
int sameRun = 0;
for (int i = 0, prev = -1; i < s.length; prev = s[i++]) {
if (s[i] != prev) {
sum -= sameRun * (sameRun + 1) / 2 - sameRun;
sameRun = 1;
} else {
sameRun++;
}
}
return sum - (sameRun * (sameRun + 1) / 2 - sameRun);
}
allUniq2Substrings("aaac".toCharArray());
3
allUniq2Substrings("aabc".toCharArray());
5
allUniq2Substrings("aaa".toCharArray());
0
allUniq2Substrings("abcd".toCharArray());
6
Edit
Let me try this again. I use the above 3 invariants.
This is a subproblem of finding all substrings which contain at least 2 unique characters.
I have a method posted above which gives me unique substrings for any length. I will use it to generate substrings from a set which contains at 2 unique characters.
We only need to keep track of the longest consequent run of characters whose set length is 2. ie Any permutation of 2 unique characters. The sum of such runs gives us the total number of desired substrings.
public static int allUniq2Substrings(char s[]) {
int sum = s.length * (s.length + 1) / 2 - s.length;
int sameRun = 0;
for (int i = 0, prev = -1; i < s.length; prev = s[i++]) {
if (s[i] != prev) {
sum -= sameRun * (sameRun + 1) / 2 - sameRun;
sameRun = 1;
} else {
sameRun++;
}
}
return sum - (sameRun * (sameRun + 1) / 2 - sameRun);
}
public static int uniq2substring(char s[]) {
int last = 0, secondLast = 0;
int sum = 0;
for (int i = 1; i < s.length; i++) {
if (s[i] != s[i - 1]) {
last = i;
break;
}
}
boolean OneTwo = false;
int oneTwoIdx = -1; //alternating pattern
for (int i = last + 1; i < s.length; ++i) {
if (s[secondLast] != s[i] && s[last] != s[i]) { //detected more than 2 uniq chars
sum += allUniq2Substrings(Arrays.copyOfRange(s, secondLast, i));
secondLast = last;
last = i;
if (OneTwo) {
secondLast = oneTwoIdx;
}
OneTwo = false;
} else if (s[i] != last) { //alternating pattern detected a*b*a
OneTwo = true;
oneTwoIdx = i;
}
}
return sum + allUniq2Substrings(Arrays.copyOfRange(s, secondLast, s.length));
}
uniq2substring("abaac".toCharArray())
6
uniq2substring("aab".toCharArray())
2
uniq2substring("aabb".toCharArray())
4
uniq2substring("ab".toCharArray())
1
I think the link posted by you for the solution of the problem 2
http://coders-stop.blogspot.in/2012/09/directi-online-test-number-of.html
can we very easily be modelled for the solution of the third problem as well.
Just modify the driver program as under
int numberOfSubstrings ( string A ) {
int len = A.length();
int res = 0, j = 1, c = 1, a[2][2];
a[0][0] = A[0]; a[0][1] = 1;
for(int i=0;i<len;i++) {
>>int start = -1;
for (;j<len; j++) {
c = isInArray(a, c, A[j]);
>> if (c == 2 && start != - 1) start = j;
if(c == -1) break;
}
>>c = removeFromArray(a,A[i]);
res = (res + j - start);
}
return res;
}
The complete explanation on the derivation can be found in the link itself :)

Find all the 4 digit vampire numbers

I am solving a problem to find out all the 4 digit Vampire numbers.
A Vampire Number v=x*y is defined as a number with 'n' even number of digits formed by multiplying a pair of 'n/2'-digit numbers (where the digits are taken from the original number in any order)x and y together. If v is a vampire number, then x&y and are called its "fangs."
Examples of vampire numbers are:
1. 1260=21*60
2. 1395=15*93
3. 1530=30*51
I have tried the brute force algorithm to combine different digits of a given number and multiply them together . But this method is highly inefficient and takes up a lot of time.
Is there a more efficient algorithmic solution to this problem?
Or you can use a property of vampire numbers described on this page (linked from Wikipedia) :
An important theoretical result found by Pete Hartley:
If x·y is a vampire number then x·y == x+y (mod 9)
Proof: Let mod be the binary modulo operator and d(x) the sum of the decimal
digits of x. It is well-known that d(x) mod 9 = x mod 9, for all x.
Assume x·y is a vampire. Then it contains the same digits as x and y,
and in particular d(x·y) = d(x)+d(y). This leads to:
(x·y) mod 9 = d(x·y) mod 9 = (d(x)+d(y)) mod 9 = (d(x) mod 9 + d(y) mod 9) mod 9
= (x mod 9 + y mod 9) mod 9 = (x+y) mod 9
The solutions to the congruence are (x mod 9, y mod 9) in {(0,0),
(2,2), (3,6), (5,8), (6,3), (8,5)}
So your code could look like this :
for(int i=18; i<100; i=i+9){ // 18 is the first multiple of 9 greater than 10
for(int j=i; j<100; j=j+9){ // Start at i because as #sh1 said it's useless to check both x*y and y*x
checkVampire(i,j);
}
}
for(int i=11; i<100; i=i+9){ // 11 is the first number greater than 10 which is = 2 mod 9
for(int j=i; j<100; j=j+9){
checkVampire(i,j);
}
}
for(int i=12; i<100; i=i+9){
for(int j=i+3; j<100; j=j+9){
checkVampire(i,j);
}
}
for(int i=14; i<100; i=i+9){
for(int j=i+3; j<100; j=j+9){
checkVampire(i,j);
}
}
// We don't do the last 2 loops, again for symmetry reasons
Since they are 40 elements in each of the sets like {(x mod 9, y mod 9) = (0,0); 10 <= x <= y <= 100}, you only do 4*40 = 160 iterations, when a brute-force gives you 10ˆ4 iterations. You can do even less operations if you take into account the >= 1000 constraint, for instance you can avoid checking if j < 1000/i.
Now you can easily scale up to find vampires with more than 4 digits =)
Iterate over all possible fangs (100 x 100 = 10000 possibilities), and find if their product has the same digits as the fangs.
Yet another brute force (C) version, with a free bubble sort to boot...
#include <stdio.h>
static inline void bubsort(int *p)
{ while (1)
{ int s = 0;
for (int i = 0; i < 3; ++i)
if (p[i] > p[i + 1])
{ s = 1;
int t = p[i]; p[i] = p[i + 1]; p[i + 1] = t;
}
if (!s) break;
}
}
int main()
{ for (int i = 10; i < 100; ++i)
for (int j = i; j < 100; ++j)
{ int p = i * j;
if (p < 1000) continue;
int xd[4];
xd[0] = i % 10;
xd[1] = i / 10;
xd[2] = j % 10;
xd[3] = j / 10;
bubsort(xd);
int x = xd[0] + xd[1] * 10 + xd[2] * 100 + xd[3] * 1000;
int yd[4];
yd[0] = p % 10;
yd[1] = (p / 10) % 10;
yd[2] = (p / 100) % 10;
yd[3] = (p / 1000);
bubsort(yd);
int y = yd[0] + yd[1] * 10 + yd[2] * 100 + yd[3] * 1000;
if (x == y)
printf("%2d * %2d = %4d\n", i, j, p);
}
return 0;
}
Runs pretty much instantaneously. Variable names aren't too descriptive, but should be pretty obvious...
The basic idea is to start with two potential fangs, break them down into digits, and sort the digits for easy comparison. Then we do the same with the product - break it down to digits and sort. Then we re-constitute two integers from the sorted digits, and if they're equal, we have a match.
Possible improvements: 1) start j at 1000 / i instead of i to avoid having to do if (p < 1000) ..., 2) maybe use insertion sort instead of bubble sort (but who's gonna notice those 2 extra swaps?), 3) use a real swap() implementation, 4) compare the arrays directly rather than building a synthetic integer out of them. Not sure any of those would make any measurable difference, though, unless you run it on a Commodore 64 or something...
Edit: Just out of curiosity, I took this version and generalized it a bit more to work for the 4, 6 and 8 digit cases - without any major optimization, it can find all the 8-digit vampire numbers in < 10 seconds...
This is an ugly hack (brute force, manual checking for permutations, unsafe buffer operations, produces dupes, etc.) but it does the job. Your new exercise is to improve it :P
Wikipedia claims that there are 7 vampire numbers which are 4 digits long. The full code has found them all, even some duplicates.
Edit: Here's a slightly better comparator function.
Edit 2: Here's a C++ version that uniques results (therefore it avoids duplicates) using an std::map (and stores the last occurrence of the particular vampire number along with its factors in it). It also meets the criterion that at least one of the factors should not end with 0, i. e. a number is not a vampire number if both of the multiplicands are divisible by then. This test looks for 6-digit vampire numbers and it does indeed find exactly 148 of them, in accordance with what Wikipedia sates.
The original code:
#include <stdio.h>
void getdigits(char buf[], int n)
{
while (n) {
*buf++ = n % 10;
n /= 10;
}
}
int is_vampire(const char n[4], const char i[2], const char j[2])
{
/* maybe a bit faster if unrolled manually */
if (i[0] == n[0]
&& i[1] == n[1]
&& j[0] == n[2]
&& j[1] == n[3])
return 1;
if (i[0] == n[1]
&& i[1] == n[0]
&& j[0] == n[2]
&& j[1] == n[3])
return 1;
if (i[0] == n[0]
&& i[1] == n[1]
&& j[0] == n[3]
&& j[1] == n[2])
return 1;
if (i[0] == n[1]
&& i[1] == n[0]
&& j[0] == n[3]
&& j[1] == n[2])
return 1;
// et cetera, the following 20 repetitions are redacted for clarity
// (this really should be a loop, shouldn't it?)
return 0;
}
int main()
{
for (int i = 10; i < 100; i++) {
for (int j = 10; j < 100; j++) {
int n = i * j;
if (n < 1000)
continue;
char ndigits[4];
getdigits(ndigits, n);
char idigits[2];
char jdigits[2];
getdigits(idigits, i);
getdigits(jdigits, j);
if (is_vampire(ndigits, idigits, jdigits))
printf("%d * %d = %d\n", i, j, n);
}
}
return 0;
}
I wouldn't have given up so easily on brute force. You have distinct set of numbers, 1000 to 9999 that you must run through. I would divide up the set into some number of subsets, and then spin up threads to handle each subset.
You could further divide the work be coming up with the various combinations of each number; IIRC my discrete math, you have 4*3*2 or 24 combinations for each number to try.
A producer / consumer approach might be worthwhile.
Iteration seems fine to me, since you only need to do this once to find all the values and you can just cache them afterwards. Python (3) version that takes about 1.5 seconds:
# just some setup
from itertools import product, permutations
dtoi = lambda *digits: int(''.join(str(digit) for digit in digits))
gen = ((dtoi(*digits), digits) for digits in product(range(10), repeat=4) if digits[0] != 0)
l = []
for val, digits in gen:
for check1, check2 in ((dtoi(*order[:2]), dtoi(*order[2:])) for order in permutations(digits) if order[0] > 0 and order[2] > 0):
if check1 * check2 == val:
l.append(val)
break
print(l)
Which will give you [1260, 1395, 1435, 1530, 1827, 2187, 6880]
EDIT: full brute force that weeds out identical X and Y values...
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Vampire {
public static void main(String[] args) {
for (int x = 10; x < 100; x++) {
String sx = String.valueOf(x);
for (int y = x; y < 100; y++) {
int v = x * y;
String sy = String.valueOf(y);
String sv = String.valueOf(v);
if (sortVampire(sx + sy).equals(sortVampire(sv))) {
System.out.printf("%d * %d = %d%n", x, y, v);
}
}
}
}
private static List<Character> sortVampire(String v) {
List<Character> vc = new ArrayList<Character>();
for (int j = 0; j < v.length(); j++) {
vc.add(v.charAt(j));
}
Collections.sort(vc);
return vc;
}
}
Brute force version in C# with LINQ:
class VampireNumbers
{
static IEnumerable<int> numberToDigits(int number)
{
while(number > 0)
{
yield return number % 10;
number /= 10;
}
}
static bool isVampire(int first, int second, int result)
{
var resultDigits = numberToDigits(result).OrderBy(x => x);
var vampireDigits = numberToDigits(first)
.Concat(numberToDigits(second))
.OrderBy(x => x);
return resultDigits.SequenceEqual(vampireDigits);
}
static void Main(string[] args)
{
var vampires = from fang1 in Enumerable.Range(10, 89)
from fang2 in Enumerable.Range(10, 89)
where fang1 < fang2
&& isVampire(fang1, fang2, fang1 * fang2)
select new { fang1, fang2 };
foreach(var vampire in vampires)
{
Console.WriteLine(vampire.fang1 * vampire.fang2
+ " = "
+ vampire.fang1
+ " * "
+ vampire.fang2);
}
}
}
Similar to someone mentioned above, my method is to first find all permutations of a number, then split them in half to form two 2-digit numbers, and test if their product equal to the original number.
Another interesting discussion above is how many permutations a number can have. Here is my opinion:
(1) a number whose four digitals are the same has 1 permutation;
(2) a number who has only two different digits has 6 permutations (it doesn't matter if it contains zeros, because we don't care after permutation if it is still a 4-digit number);
(3) a number who has three different digits has 12 permutations;
(4) a number with all four different digits has 24 permutations.
public class VampireNumber {
// method to find all permutations of a 4-digit number
public static void permuta(String x, String s, int v)
{for(int i = 0; i < s.length(); i++)
{permuta( x + s.charAt(i), s.substring(0,i) + s.substring(i+1), v);
if (s.length() == 1)
{x = x + s;
int leftpart = Integer.parseInt(x.substring(0,2));
int rightpart = Integer.parseInt(x.substring(2));
if (leftpart*rightpart == v)
{System.out.println("Vampir = " + v);
}
}
}
}
public static void main(String[] args){
for (int i = 1000; i < 10000; i++) {
permuta("", Integer.toString(i), i); //convert the integer to a string
}
}
}
The approach I would try would be to loop through each number in [1000, 9999], and test if any permutation of its digits (split in the middle) multiplied to make it.
This will require (9999 - 1000) * 24 = 215,976 tests, which should execute acceptably fast on a modern machine.
I would definitely store the digits separately, so you can avoid having to do something like a bunch of division to extract the digits from a single integer.
If you write your code such that you're only ever doing integer addition and multiplication (and maybe the occasional division to carry), it should be pretty fast. You could further increase the speed by skipping two-digit pairs which "obviously" won't work - e.g., ones with leading zeros (note that the largest product than can be produced by a one digit number and a two digit number is 9 * 99, or 891).
Also note that this approach is embarassingly parallel (http://en.wikipedia.org/wiki/Embarrassingly_parallel), so if you really need to speed it up even more then you should look into testing the numbers in separate threads.
<?php
for ($i = 10; $i <= 99; $j++) {
// Extract digits
$digits = str_split($i);
// Loop through 2nd number
for ($j = 10; $j <= 99; $j++) {
// Extract digits
$j_digits = str_split($j);
$digits[2] = $j_digits[0];
$digits[3] = $j_digits[1];
$product = $i * $j;
$product_digits = str_split($product);
// check if fangs
$inc = 0;
while (in_array($digits[$inc], $product_digits)) {
// Remove digit from product table
/// So AAAA -> doesnt match ABCD
unset($product_digits[$array_serach($digits[$inc], $product_digits)]);
$inc++;
// If reached 4 -> vampire number
if ($inc == 4) {
$vampire[] = $product;
break;
}
}
}
}
// Print results
print_r($vampire);
?>
Took less than a second on PHP. couldn't even tell it had to run 8100 computations... computers are fast!
Results:
Gives you all the 4 digits plus some are repeated. You can further process the data and remove duplicates.
It seems to me that to perform the fewest possible tests without relying on any particularly abstract insights, you probably want to iterate over the fangs and cull any obviously pointless candidates.
For example, since x*y == y*x about half your search space can be eliminated by only evaluating cases where y > x. If the largest two-digit fang is 99 then the smallest which can make a four-digit number is 11, so don't start lower than 11.
EDIT:
OK, throwing everything I thought of into the mix (even though it looks silly against the leading solution).
for (x = 11; x < 100; x++)
{
/* start y either at x, or if x is too small then 1000 / x */
for (y = (x * x < 1000 ? 1000 / x : x); y < 100; y++)
{
int p = x * y;
/* if sum of digits in product is != sum of digits in x+y, then skip */
if ((p - (x + y)) % 9 != 0)
continue;
if (is_vampire(p, x, y))
printf("%d\n", p);
}
}
and the test, since I haven't seen anyone use a histogram, yet:
int is_vampire(int p, int x, int y)
{
int h[10] = { 0 };
int i;
for (i = 0; i < 4; i++)
{
h[p % 10]++;
p /= 10;
}
for (i = 0; i < 2; i++)
{
h[x % 10]--;
h[y % 10]--;
x /= 10;
y /= 10;
}
for (i = 0; i < 10; i++)
if (h[i] != 0)
return 0;
return 1;
}
1260 1395 1435 1530 1827 2187 6880 is vampire
I am new to programming... But there are only 12 combinations in finding all 4-digit vampire numbers. My poor answer is:
public class VampNo {
public static void main(String[] args) {
for(int i = 1000; i < 10000; i++) {
int a = i/1000;
int b = i/100%10;
int c = i/10%10;
int d = i%10;
if((a * 10 + b) * (c * 10 + d) == i || (b * 10 + a) * (d * 10 + c) == i ||
(a * 10 + d) * (b * 10 + c) == i || (d * 10 + a) * (c * 10 + b) == i ||
(a * 10 + c) * (b * 10 + d) == i || (c * 10 + a) * (d * 10 + b) == i ||
(a * 10 + b) * (d * 10 + c) == i || (b * 10 + a) * (c * 10 + d) == i ||
(b * 10 + c) * (d * 10 + a) == i || (c * 10 + b) * (a * 10 + d) == i ||
(a * 10 + c) * (d * 10 + b) == i || (c * 10 + a) * (b * 10 + d) == i)
System.out.println(i + " is vampire");
}
}
}
The main task now is to simplify boolean expression in If() block
I've edited Owlstead's algorithm a bit to make it more understandable to Java beginners/learners.
import java.util.Arrays;
public class Vampire {
public static void main(String[] args) {
for (int x = 10; x < 100; x++) {
String sx = Integer.toString(x);
for (int y = x; y < 100; y++) {
int v = x * y;
String sy = Integer.toString(y);
String sv = Integer.toString(v);
if( Arrays.equals(sortVampire(sx + sy), sortVampire(sv)))
System.out.printf("%d * %d = %d%n", x, y, v);
}
}
}
private static char[] sortVampire (String v){
char[] sortedArray = v.toCharArray();
Arrays.sort(sortedArray);
return sortedArray;
}
}
This python code run very fast (O(n2))
result = []
for i in range(10,100):
for j in range(10, 100):
list1 = []
list2 = []
k = i * j
if k < 1000 or k > 10000:
continue
else:
for item in str(i):
list1.append(item)
for item in str(j):
list1.append(item)
for item in str(k):
list2.append(item)
flag = 1
for each in list1:
if each not in list2:
flag = 0
else:
list2.remove(each)
for each in list2:
if each not in list1:
flag = 0
if flag == 1:
if k not in result:
result.append(k)
for each in result:
print(each)
And here is my code. To generate zombie numbers we need to use Random class :)
import java.io.PrintStream;
import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;
class VampireNumbers {
static PrintStream p = System.out;
private static Set<Integer> findVampireNumber() {
Set<Integer> vampireSet = new HashSet<Integer>();
for (int y = 1000; y <= 9999; y++) {
char[] numbersSeparately = ("" + y).toCharArray();
int numberOfDigits = numbersSeparately.length;
for (int i = 0; i < numberOfDigits; i++) {
for (int j = 0; j < numberOfDigits; j++) {
if (i != j) {
int value1 = Integer.valueOf("" + numbersSeparately[i] + numbersSeparately[j]);
int ki = -1;
for (int k = 0; k < numberOfDigits; k++) {
if (k != i && k != j) {
ki = k;
}
}
int kj = -1;
for (int t = 0; t < numberOfDigits; t++) {
if (t != i && t != j && t != ki) {
kj = t;
}
}
int value21 = Integer.valueOf("" + numbersSeparately[ki] + numbersSeparately[kj]);
int value22 = Integer.valueOf("" + numbersSeparately[kj] + numbersSeparately[ki]);
if (value1 * value21 == y && !(numbersSeparately[j] == 0 && numbersSeparately[kj] == 0)
|| value1 * value22 == y
&& !(numbersSeparately[j] == 0 && numbersSeparately[ki] == 0)) {
vampireSet.add(y);
}
}
}
}
}
return vampireSet;
}
public static void main(String[] args) {
Set<Integer> vampireSet = findVampireNumber();
Iterator<Integer> i = vampireSet.iterator();
int number = 1;
while (i.hasNext()) {
p.println(number + ": " + i.next());
number++;
}
}
}

Algorithm for digit summing?

I'm searching for an algorithm for Digit summing. Let me outline the basic principle:
Say you have a number: 18268.
1 + 8 + 2 + 6 + 8 = 25
2 + 5 = 7
And 7 is our final number. It's basically adding each number of the whole number until we get down to a single (also known as a 'core') digit. It's often used by numerologists.
I'm searching for an algorithm (doesn't have to be language in-specific) for this. I have searched Google for the last hour with terms such as digit sum algorithm and whatnot but got no suitable results.
Because 10-1=9, a little number theory will tell you that the final answer is just n mod 9. Here's code:
ans = n%9;
if(ans==0 && n>0) ans=9;
return ans;
Example: 18268%9 is 7. (Also see: Casting out nines.)
I would try this:
int number = 18268;
int core = number;
int total = 0;
while(core > 10)
{
total = 0;
number = core;
while(number > 0)
{
total += number % 10;
number /= 10;
}
core = total;
}
Doesn't work with negative numbers, but I don't know how you would handle it anyhow. You can also change f(x) to be iterative:
sum( x ) =
while ( ( x = f( x ) ) >= 10 );
return x;
f( x ) =
if ( x >= 10 ) return f( x / 10 ) + x % 10
return x
You can also take advantage of number theory, giving you this f(x):
f( x ) =
if ( x == 0 ) return 0
return x % 9
Mod the whole number by 10.
Add the number to an array.
Add the whole array.
int number = 18268;
int total = 0;
while(number > 0)
{
total += number % 10;
total = total%10;
number /= 10;
}
this is from a really long time ago, but the best solution i have for this is:
int digitSum(int num){
if (num < 10) return num;
else return (n-1)%9+1;
}
I don't know how much better this is,but it will account for the divisible by 9 numbers easily. Just a cool algorithm.
private static int sum(long number) {
int sum = 0;
if (number == 0) {
return 0;
}
do {
int last = (int) (number % 10);
sum = (sum + last) % 9;
} while ((number /= 10) > 0);
return sum == 0 ? 9 : sum;
}
public int DigitSum(long n)
{
return (int)(1 + (n - 1) % 9);
}

Resources