Related
My objective is to find the sum of all numbers from 4 to 666554 which consists of 4,5,6 only.
SUM = 4+5+6+44+45+46+54+55+56+64+65+66+.....................+666554.
Simple method is to run a loop and add the numbers made of 4,5 and 6 only.
long long sum = 0;
for(int i=4;i <=666554;i++){
/*check if number contains only 4,5 and 6.
if condition is true then add the number to the sum*/
}
But it seems to be inefficient. Checking that the number is made up of 4,5 and 6 will take time. Is there any way to increase the efficiency. I have tried a lot but no new approach i have found.Please help.
For 1-digit numbers, note that
4 + 5 + 6 == 5 * 3
For 2-digits numbers:
(44 + 45 + 46) + (54 + 55 + 56) + (64 + 65 + 66)
== 45 * 3 + 55 * 3 + 65 * 3
== 55 * 9
and so on.
In general, for n-digits numbers, there are 3n of them consist of 4,5,6 only, their average value is exactly 5...5(n digits). Using code, the sum of them is ('5' * n).to_i * 3 ** n (Ruby), or int('5' * n) * 3 ** n (Python).
You calculate up to 6-digits numbers, then subtract the sum of 666555 to 666666.
P.S: for small numbers like 666554, using pattern matching is fast enough. (example)
Implement a counter in base 3 (number of digit values), e.g. 0,1,2,10,11,12,20,21,22,100.... and then translate the base-3 number into a decimal with the digits 4,5,6 (0->4, 1->5, 2->6), and add to running total. Repeat until the limit.
def compute_sum(digits, max_val):
def _next_val(cur_val):
for pos in range(len(cur_val)):
cur_val[pos]+=1
if cur_val[pos]<len(digits):
return
cur_val[pos]=0
cur_val.append(0)
def _get_val(cur_val):
digit_val=1
num_val=0
for x in cur_val:
num_val+=digits[x]*digit_val
digit_val*=10
return num_val
cur_val=[]
sum=0
while(True):
_next_val(cur_val)
num_val=_get_val(cur_val)
if num_val>max_val:
break
sum+=num_val
return sum
def main():
digits=[4,5,6]
max_val=666554
print(digits, max_val)
print(compute_sum(digits, max_val))
Mathematics are good, but not all problems are trivially "compressible", so knowing how to deal with them without mathematics can be worthwhile.
In this problem, the summation is trivial, the difficulty is efficiently enumerating the numbers that need be added, at first glance.
The "filter" route is a possibility: generate all possible numbers, incrementally, and filter out those which do not match; however it is also quite inefficient (in general):
the condition might not be trivial to match: in this case, the easier way is a conversion to string (fairly heavy on divisions and tests) followed by string-matching
the ratio of filtering is not too bad to start with at 30% per digit, but it scales very poorly as gen-y-s remarked: for a 4 digits number it is at 1%, or generating and checking 100 numbers to only get 1 out of them.
I would therefore advise a "generational" approach: only generate numbers that match the condition (and all of them).
I would note that generating all numbers composed of 4, 5 and 6 is like counting (in ternary):
starts from 4
45 becomes 46 (beware of carry-overs)
66 becomes 444 (extreme carry-over)
Let's go, in Python, as a generator:
def generator():
def convert(array):
i = 0
for e in array:
i *= 10
i += e
return i
def increment(array):
result = []
carry = True
for e in array[::-1]:
if carry:
e += 1
carry = False
if e > 6:
e = 4
carry = True
result = [e,] + result
if carry:
result = [4,] + result
return result
array = [4]
while True:
num = convert(array)
if num > 666554: break
yield num
array = increment(array)
Its result can be printed with sum(generator()):
$ time python example.py
409632209
python example.py 0.03s user 0.00s system 82% cpu 0.043 total
And here is the same in C++.
"Start with a simpler problem." —Polya
Sum the n-digit numbers which consist of the digits 4,5,6 only
As Yu Hao explains above, there are 3**n numbers and their average by symmetry is eg. 555555, so the sum is 3**n * (10**n-1)*5/9. But if you didn't spot that, here's how you might solve the problem another way.
The problem has a recursive construction, so let's try a recursive solution. Let g(n) be the sum of all 456-numbers of exactly n digits. Then we have the recurrence relation:
g(n) = (4+5+6)*10**(n-1)*3**(n-1) + 3*g(n-1)
To see this, separate the first digit of each number in the sum (eg. for n=3, the hundreds column). That gives the first term. The second term is sum of the remaining digits, one count of g(n-1) for each prefix of 4,5,6.
If that's still unclear, write out the n=2 sum and separate tens from units:
g(2) = 44+45+46 + 54+55+56 + 64+65+66
= (40+50+60)*3 + 3*(4+5+6)
= (4+5+6)*10*3 + 3*g(n-1)
Cool. At this point, the keen reader might like to check Yu Hao's formula for g(n) satisfies our recurrence relation.
To solve OP's problem, the sum of all 456-numbers from 4 to 666666 is g(1) + g(2) + g(3) + g(4) + g(5) + g(6). In Python, with dynamic programming:
def sum456(n):
"""Find the sum of all numbers at most n digits which consist of 4,5,6 only"""
g = [0] * (n+1)
for i in range(1,n+1):
g[i] = 15*10**(i-1)*3**(i-1) + 3*g[i-1]
print(g) # show the array of partial solutions
return sum(g)
For n=6
>>> sum456(6)
[0, 15, 495, 14985, 449955, 13499865, 404999595]
418964910
Edit: I note that OP truncated his sum at 666554 so it doesn't fit the general pattern. It will be less the last few terms
>>> sum456(6) - (666555 + 666556 + 666564 + 666565 + 666566 + 666644 + 666645 + 666646 + 666654 + 666655 + 666656 + + 666664 + 666665 + 666666)
409632209
The sum of 4 through 666666 is:
total = sum([15*(3**i)*int('1'*(i+1)) for i in range(6)])
>>> 418964910
The sum of the few numbers between 666554 and 666666 is:
rest = 666555+666556+666564+666565+666566+
666644+666645+666646+
666654+666655+666656+
666664+666665+666666
>>> 9332701
total - rest
>>> 409632209
Java implementation of question:-
This uses the modulo(10^9 +7) for the answer.
public static long compute_sum(long[] digits, long max_val, long count[]) {
List<Long> cur_val = new ArrayList<>();
long sum = 0;
long mod = ((long)Math.pow(10,9))+7;
long num_val = 0;
while (true) {
_next_val(cur_val, digits);
num_val = _get_val(cur_val, digits, count);
sum =(sum%mod + (num_val)%mod)%mod;
if (num_val == max_val) {
break;
}
}
return sum;
}
public static void _next_val(List<Long> cur_val, long[] digits) {
for (int pos = 0; pos < cur_val.size(); pos++) {
cur_val.set(pos, cur_val.get(pos) + 1);
if (cur_val.get(pos) < digits.length)
return;
cur_val.set(pos, 0L);
}
cur_val.add(0L);
}
public static long _get_val(List<Long> cur_val, long[] digits, long count[]) {
long digit_val = 1;
long num_val = 0;
long[] digitAppearanceCount = new long[]{0,0,0};
for (Long x : cur_val) {
digitAppearanceCount[x.intValue()] = digitAppearanceCount[x.intValue()]+1;
if (digitAppearanceCount[x.intValue()]>count[x.intValue()]){
num_val=0;
break;
}
num_val = num_val+(digits[x.intValue()] * digit_val);
digit_val *= 10;
}
return num_val;
}
public static void main(String[] args) {
long [] digits=new long[]{4,5,6};
long count[] = new long[]{1,1,1};
long max_val= 654;
System.out.println(compute_sum(digits, max_val, count));
}
The Answer by #gen-y-s (https://stackoverflow.com/a/31286947/8398943) is wrong (It includes 55,66,44 for x=y=z=1 which is exceeding the available 4s, 5s, 6s). It gives output as 12189 but it should be 3675 for x=y=z=1.
The logic by #Yu Hao (https://stackoverflow.com/a/31285816/8398943) has the same mistake as mentioned above. It gives output as 12189 but it should be 3675 for x=y=z=1.
The puzzle
For every input number n (n < 10) there is an output number m such that:
m's first digit is n
m is an n digit number
every 2 digit sequence inside m must be a different prime number
The output should be m where m is the smallest number that fulfils the conditions above. If there is no such number, the output should be -1;
Examples
n = 3 -> m = 311
n = 4 -> m = 4113 (note that this is not 4111 as that would be repeating 11)
n = 9 -> m = 971131737
My somewhat working solution
Here's my first stab at this, the "brute force" approach. I am looking for a more elegant solution as this is very inefficient as n grows larger.
public long GetM(int n)
{
long start = n * (long)Math.Pow((double)10, (double)n - 1);
long end = n * (long)Math.Pow((double)10, (double)n);
for (long x = start; x < end; x++)
{
long xCopy = x;
bool allDigitsPrime = true;
List<int> allPrimeNumbers = new List<int>();
while (xCopy >= 10)
{
long lastDigitsLong = xCopy % 100;
int lastDigits = (int)lastDigitsLong;
bool lastDigitsSame = allPrimeNumbers.Count != 0 && allPrimeNumbers.Contains(lastDigits);
if (!IsPrime(lastDigits) || lastDigitsSame)
{
allDigitsPrime = false;
break;
}
xCopy /= 10;
allPrimeNumbers.Add(lastDigits);
}
if (n != 1 && allDigitsPrime)
{
return x;
}
}
return -1;
}
Initial thoughts on how this could be made more efficient
So, clearly the bottleneck here is traversing through the whole list of numbers that could fulfil this condition from n.... to (n+1).... . Instead of simply incrementing the number of every iteration of the loop, there must be some clever way of skipping numbers based on the requirement that the 2 digit sequences must be prime. For instance for n = 5, there is no point going through 50000 - 50999 (50 isn't prime), 51200 - 51299 (12 isn't prime), but I wasn't quite sure how this could be implemented or if it would be enough of an optimization to make the algorithm run for n=9.
Any ideas on this approach or a different optimization approach?
You don't have to try all numbers. You can instead use a different strategy, summed up as "try appending a digit".
Which digit? Well, a digit such that
it forms a prime together with your current last digit
the prime formed has not occurred in the number before
This should be done recursively (not iteratively), because you may run out of options and then you'd have to backtrack and try a different digit earlier in the number.
This is still an exponential time algorithm, but it avoids most of the search space because it never tries any numbers that don't fit the rule that every pair of adjacent digits must form a prime number.
Here's a possible solution, in R, using recursion . It would be interesting to build a tree of all the possible paths
# For every input number n (n < 10)
# there is an output number m such that:
# m's first digit is n
# m is an n digit number
# every 2 digit sequence inside m must be a different prime number
# Need to select the smallest m that meets the criteria
library('numbers')
mNumHelper <- function(cn,n,pr,cm=NULL) {
if (cn == 1) {
if (n==1) {
return(1)
}
firstDigit <- n
} else {
firstDigit <- mod(cm,10)
}
possibleNextNumbers <- pr[floor(pr/10) == firstDigit]
nPossible = length(possibleNextNumbers)
if (nPossible == 1) {
nextPrime <- possibleNextNumbers
} else{
# nextPrime <- sample(possibleNextNumbers,1)
nextPrime <- min(possibleNextNumbers)
}
pr <- pr[which(pr!=nextPrime)]
if (is.null(cm)) {
cm <- nextPrime
} else {
cm = cm * 10 + mod(nextPrime,10)
}
cn = cn + 1
if (cn < n) {
cm = mNumHelper(cn,n,pr,cm)
}
return(cm)
}
mNum <- function(n) {
pr<-Primes(10,100)
m <- mNumHelper(1,n,pr)
}
for (i in seq(1,9)) {
print(paste('i',i,'m',mNum(i)))
}
Sample output
[1] "i 1 m 1"
[1] "i 2 m 23"
[1] "i 3 m 311"
[1] "i 4 m 4113"
[1] "i 5 m 53113"
[1] "i 6 m 611317"
[1] "i 7 m 7113173"
[1] "i 8 m 83113717"
[1] "i 9 m 971131737"
Solution updated to select the smallest prime from the set of available primes, and remove bad path check since it's not required.
I just made a list of the two-digit prime numbers, then solved the problem by hand; it took only a few minues. Not every problem requires a computer!
I have got one question to print one million prime numbers . I have written a java program for that .. It's currently taking 1.5 mins approx to calculate it .. I think my solution is not that efficient. I have used the below algo:
Adding 1 2 3 to the prime list initially
Calculating the last digit of the number to be checked
Checking if the digit is 0 , 2 or 4 or 6 or 8 then skipping the number
else calculating the square root of the number ..
Trying to Divide the number starting from 2 till the square root of the number
if number is divisible then skipping the number else adding it to the prime list
I have read several other solutions as well , but I didn't find a good answer. Please suggest ideally what should be approx minimum time to calculate this and what changes are required to make the algorithm more efficient.
If you added 1 to your list, your answer is wrong already :)
Anyway, Sieve of Erathosthenes is where you should begin, it's incredibly simple and quite efficient.
Once you're familiar with the idea of sieves and how they work, you can move on to Sieve of Atkin, which is a bit more complicated but obviously more efficient.
Key things:
Skip all even numbers. Start with 5, and just add two at a time.
1 isn't a prime number...
Test a number by finding the mod of all prime numbers till the square root of the number. No need to test anything but primes.
A simple sieve of Eratosthenes runs like the clappers. This calculates the 1,000,000th prime in less than a second on my box:
class PrimeSieve
{
public List<int> Primes;
private BitArray Sieve;
public PrimeSieve(int max)
{
Primes = new List<int> { 2, 3 }; // Must include at least 2, 3.
Sieve = new BitArray(max + 1);
foreach (var p in Primes)
for (var i = p * p; i < Sieve.Length; i += p) Sieve[i] = true;
}
public int Extend()
{
var p = Primes.Last() + 2; // Skip the even numbers.
while (Sieve[p]) p += 2;
for (var i = p * p; i < Sieve.Length; i += p) Sieve[i] = true;
Primes.Add(p);
return p;
}
}
EDIT: sieving optimally starts from p^2, not 2p, as Will Ness correctly points out (all compound numbers below p^2 will have been marked in earlier iterations).
You might want to implement Sieve of Eratosthenes algorithm to find prime numbers from 1 to n and iteratively increase the range while you are doing it if needed to. (i.e. did not find 1,000,000 primes yet)
First, 1 is not a prime number.
Second, the millionth prime is 15,485,863, so you need to be prepared for some large data-handling.
Third, you probably want to use the Sieve of Eratosthenes; here's a simple version:
function sieve(n)
bits := makeArray(0..n, True)
for p from 2 to n step 1
if bits[p]
output p
for i from p*p to n step p
bits[i] := False
That may not work for the size of array that you will need to calculate the first million primes. In that case, you will want to implement a Segmented Sieve of Eratosthenes.
I've done a lot of work with prime numbers at my blog, including an essay that provides an optimized Sieve of Eratosthenes, with implementations in five programming languages.
No matter what you do, with any programming language, you should be able to compute the first million primes in no more than a few seconds.
Here's an Ocaml program that implements the Trial division sieve (which is sort of the inverse of Eratosthenes as correctly pointed out by Will):
(* Creates a function for streaming integers from x onward *)
let stream x =
let counter = ref (x) in
fun () ->
let _ = counter := !counter + 1 in
!counter;;
(* Filter the given stream of any multiples of x *)
let filter s x = fun () ->
let rec filter' () = match s () with
n when n mod x = 0 ->
filter' ()|
n ->
n in
filter' ();;
(* Get next prime, apply a new filter by that prime to the remainder of the stream *)
let primes count =
let rec primes' count' s = match count' with
0 ->
[]|
_ ->
let n = s () in
n :: primes' (count' - 1) (filter s n) in
primes' count (stream 1);;
It works on a stream of integers. Each time a new prime number is discovered, a filter is added to the stream so that the remainder of the stream gets filtered of any multiples of that prime number. This program can be altered to generate prime numbers on-demand as well.
It should be fairly easy to take the same approach in Java.
Hope this helps!
Here's a javascript solution that uses recursion and iteration to reach the millionth prime. It's not as fast as the Sieve of Erathosthenes, but does not require one to know the value of the millionth prime (i.e., size of the required sieve) in advance:
function findPrimes(n, current, primes) {
if (!n || current < 2) return []
var isPrime = true
for (var i = 0; i < primes.length; i++) {
if (current % primes[i] == 0) {
isPrime = false
break
}
}
if (isPrime) primes.push(current)
if (primes.length < n) return findPrimes(n, current + 1, primes)
else return primes
}
var primes = [2,3]
for (var i = 1; i <= 1000; i++) {
primes = findPrimes(i*1000, primes[primes.length - 1]+1, primes)
console.log(i*1000 + 'th prime: ' + primes[primes.length-1])
}
process.exit()
Output:
...
996000th prime: 15419293
997000th prime: 15435941
998000th prime: 15452873
999000th prime: 15469313
1000000th prime: 15485863
Process finished with exit code 0
As a fresher level I will try this one, so any improvement to make this more efficient and faster is appreciated
public static void main(String ar[]) {
ArrayList primeNumbers = new ArrayList();
for(int i = 2; primeNumbers.size() < 1000000; i++) {//first 1 million prime number
// for(int i = 2; i < 1000000; i++) {//prime numbers from 1 to 1 million
boolean divisible = false;
for(int j=2;j<i/2;j++){
if((i % j) == 0) {
divisible = true;
break;
}
}
if(divisible == false) {
primeNumbers.add(i);
// System.out.println(i + " ");
}
}
System.out.println(primeNumbers);
}
Adding 1 2 3 to the prime list initially
Actually, just 2 is sufficient. Hard-coding 3 might save, at most, a millisecond. There's no need to harp on 1. I am convinced that including it was an honest mistake. You already knew, and working on this program would have helped confirm this.
Calculating the last digit of the number to be checked
The last digit? In what base? Base 10? I think this might be your problem.
Checking if the digit is 0, 2 or 4 or 6 or 8 then skipping the number
else calculating the square root of the number
I think this is where the problem lies. Your program should simply skip even numbers, because, aside from −2 and 2, they're all composite. On the other hand, this won't halve running time because odd numbers like 91 and and 2209 might require more effort to be ruled out as not prime.
Trying to Divide the number starting from 2 till the square root of the number
if number is divisible then skipping the number else adding it to the prime list
Does "2 till the square root of the number" include numbers like 4, 6 and 9? The only potential factors that need to be checked are numbers that have already been proven prime. If n is not divisible by 7, it won't be divisible by 49 either. If you're building up a list, you might as well use it to check potential primes.
Benchmarking Java's a little difficult because you're at the mercy of the runtime system. Still, a minute and a half, while it would have been considered miraculous by Mersenne, is too slow today. Five, ten seconds, that I'd find acceptable.
Maybe this is one of those cases where you should avoid the use of objects in favor of an array of primitives. My first draft took even longer than yours. Eventually I came up with this:
static int[] fillWithPrimes(int quantity) {
int[] primes = new int[quantity];
primes[0] = 2;
int currPi = 1;
int currIndex = 0;
int currNum = 3;
int currPrime;
boolean coPrimeFlag;
double squareRoot;
while (currPi < quantity) {
squareRoot = Math.sqrt(currNum);
do {
currPrime = primes[currIndex];
coPrimeFlag = (currNum % currPrime != 0);
currIndex++;
} while (coPrimeFlag && currPrime <= squareRoot);
if (coPrimeFlag) {
primes[currPi] = currNum;
currPi++;
}
currNum += 2;
currIndex = 0;
}
return primes;
}
Then I wrote a main() that notes the time before calling fillWithPrimes() with a quantity parameter of 1,000,000, and reports on the results:
run:
Operation took 2378 milliseconds
10th prime is 29
100th prime is 541
1000th prime is 7919
10000th prime is 104729
100000th prime is 1299709
1000000th prime is 15485863
BUILD SUCCESSFUL (total time: 2 seconds)
I'm sure it can be optimized further. Me, personally, I'm satisfied with two and a half seconds.
Isn't everything after 5 ending in a five divisible by 5 as well, so you can skip things who's right(1,numb)<>"5" for example 987,985. I made one in Excel that will test a million numbers for primes and spit them in a column in about 15 seconds but it gets crazy around 15 million
It's an interview question.
Given a number n, find out how many numbers have digit 2 in the range 0...n
For example ,
input = 13 output = 2 (2 and 12)
I gave the usual O(n^2) solution but is there a better approach.
is there any 'trick' formula that will help me to get the answer right away
Count the numbers that do not have the digit 2. Among the numbers less than 10k, there are exactly 9k of them. Then it remains to treat the numbers from 10k to n, where
10^k <= n < 10^(k+1)
which you can do by treating the first digits individually (the cases 2 and others have to be differentiated), and then the first 2 digits etc.
For example, for n = 2345, we find there are 9^3 = 729 numbers without the digit 2 below 1000. There are again 729 such numbers in the range from 1000 to 1999. Then in the range from 2000 to 2345, there are none, for a total of 1458, hence the numbers containing the digit 2 are
2345 - 1458 = 887
argument 'digit' is the one which we want to count and arg 'number' is till where we want to count. For eg: If we want to count occurrences of '1', from 0 to 12, call the function with digit=1, and number=12, and it will return the number of occurrences of '1'.
int countOccurrences(int digit, int number)
{
int counter = 0;
for(int i=1; i<number; i++)
{
int j = i;
while(j > 0)
{
if(j%10 == digit)
counter++;
j /= 10;
}
}
return counter;
}
Given the number with the digits ABCDEF you can count the number of '2's in the ranges [0,F], [0,E9], [0,D99], [0,C999], [0,B9999] and [0,A99999] and add them.
Then for the range [0, X9999...999], the top number T = X9999...999 can be written as (X+1) * 10<sup>nines</sup> -1.
The number of '2's in that range is:
((X >= 2 ? 1/(X + 1)) : 0) + nines/10 ) * (T + 1);
That is: if X >= 2, the fraction of numbers that have a '2' at the position nines+1 is 1/(X+1), In total there are (T+1)/(X+1) '2's at that position. If X < 2, then no number on [0..T] has a '2' at that position.
For the other digit positions, is easy to see that at every digit position, 1/10 of the numbers have a '2', so there are (T+1)/10 '2's at position 0, (T+1)/10 '2's at position 1, etc. In total, (T+1) * nines / 10.
The complexity of this solution is O(logN).
this is how I would go about coding my first draft (Python code)
def count2(n) :
return [p for p in range(n+1) if '2' in str(p)]
and that will return you a list with the containing number.
In terms of performance it is not that bad, for n=10,000,000 an average iteration takes about 5.5 seconds
Let me start with an example -
I have a range of numbers from 1 to 9. And let's say the target number that I want is 29.
In this case the minimum number of operations that are required would be (9*3)+2 = 2 operations. Similarly for 18 the minimum number of operations is 1 (9*2=18).
I can use any of the 4 arithmetic operators - +, -, / and *.
How can I programmatically find out the minimum number of operations required?
Thanks in advance for any help provided.
clarification: integers only, no decimals allowed mid-calculation. i.e. the following is not valid (from comments below): ((9/2) + 1) * 4 == 22
I must admit I didn't think about this thoroughly, but for my purpose it doesn't matter if decimal numbers appear mid-calculation. ((9/2) + 1) * 4 == 22 is valid. Sorry for the confusion.
For the special case where set Y = [1..9] and n > 0:
n <= 9 : 0 operations
n <=18 : 1 operation (+)
otherwise : Remove any divisor found in Y. If this is not enough, do a recursion on the remainder for all offsets -9 .. +9. Offset 0 can be skipped as it has already been tried.
Notice how division is not needed in this case. For other Y this does not hold.
This algorithm is exponential in log(n). The exact analysis is a job for somebody with more knowledge about algebra than I.
For more speed, add pruning to eliminate some of the search for larger numbers.
Sample code:
def findop(n, maxlen=9999):
# Return a short postfix list of numbers and operations
# Simple solution to small numbers
if n<=9: return [n]
if n<=18: return [9,n-9,'+']
# Find direct multiply
x = divlist(n)
if len(x) > 1:
mults = len(x)-1
x[-1:] = findop(x[-1], maxlen-2*mults)
x.extend(['*'] * mults)
return x
shortest = 0
for o in range(1,10) + range(-1,-10,-1):
x = divlist(n-o)
if len(x) == 1: continue
mults = len(x)-1
# We spent len(divlist) + mults + 2 fields for offset.
# The last number is expanded by the recursion, so it doesn't count.
recursion_maxlen = maxlen - len(x) - mults - 2 + 1
if recursion_maxlen < 1: continue
x[-1:] = findop(x[-1], recursion_maxlen)
x.extend(['*'] * mults)
if o > 0:
x.extend([o, '+'])
else:
x.extend([-o, '-'])
if shortest == 0 or len(x) < shortest:
shortest = len(x)
maxlen = shortest - 1
solution = x[:]
if shortest == 0:
# Fake solution, it will be discarded
return '#' * (maxlen+1)
return solution
def divlist(n):
l = []
for d in range(9,1,-1):
while n%d == 0:
l.append(d)
n = n/d
if n>1: l.append(n)
return l
The basic idea is to test all possibilities with k operations, for k starting from 0. Imagine you create a tree of height k that branches for every possible new operation with operand (4*9 branches per level). You need to traverse and evaluate the leaves of the tree for each k before moving to the next k.
I didn't test this pseudo-code:
for every k from 0 to infinity
for every n from 1 to 9
if compute(n,0,k):
return k
boolean compute(n,j,k):
if (j == k):
return (n == target)
else:
for each operator in {+,-,*,/}:
for every i from 1 to 9:
if compute((n operator i),j+1,k):
return true
return false
It doesn't take into account arithmetic operators precedence and braces, that would require some rework.
Really cool question :)
Notice that you can start from the end! From your example (9*3)+2 = 29 is equivalent to saying (29-2)/3=9. That way we can avoid the double loop in cyborg's answer. This suggests the following algorithm for set Y and result r:
nextleaves = {r}
nops = 0
while(true):
nops = nops+1
leaves = nextleaves
nextleaves = {}
for leaf in leaves:
for y in Y:
if (leaf+y) or (leaf-y) or (leaf*y) or (leaf/y) is in X:
return(nops)
else:
add (leaf+y) and (leaf-y) and (leaf*y) and (leaf/y) to nextleaves
This is the basic idea, performance can be certainly be improved, for instance by avoiding "backtracks", such as r+a-a or r*a*b/a.
I guess my idea is similar to the one of Peer Sommerlund:
For big numbers, you advance fast, by multiplication with big ciphers.
Is Y=29 prime? If not, divide it by the maximum divider of (2 to 9).
Else you could subtract a number, to reach a dividable number. 27 is fine, since it is dividable by 9, so
(29-2)/9=3 =>
3*9+2 = 29
So maybe - I didn't think about this to the end: Search the next divisible by 9 number below Y. If you don't reach a number which is a digit, repeat.
The formula is the steps reversed.
(I'll try it for some numbers. :) )
I tried with 2551, which is
echo $((((3*9+4)*9+4)*9+4))
But I didn't test every intermediate result whether it is prime.
But
echo $((8*8*8*5-9))
is 2 operations less. Maybe I can investigate this later.