Finding Digit Strings In Powers Of Two
September 24, 2013
We compute all the powers of two and save them in the closure of the search function so they only have to be computed once instead of each time a search is performed. We keep track of the powers of two and double at each step instead of recomputing each time from scratch:
(define search
(let ((twos (make-vector 10000)))
(do ((i 0 (+ i 1)) (t 1 (* t 2))) ((= i 10000))
(vector-set! twos i (number->string t)))
(lambda (target)
(let loop ((i 0))
(cond ((= i 10000) #f)
((string-find (number->string target)
(vector-ref twos i)) i)
(else (loop (+ i 1))))))))
The powers of two are stored as strings, and the search in the body of the function calls string-find
from the Standard Prelude to search each power of two. Here are some examples:
> (search 42)
19
> (search 1234567)
8792
This task was easy for us because Scheme provides big integers and conversions to strings natively; it will be harder in languages that don’t provide those features. You can run the program at http://programmingpraxis.codepad.org/hEsGGLRz.
Rather easy in Python. The functions returns -1 of no index is found.
I rather like Haskell’s
Maybe
.Graham: The corresponding idiom in Scheme is to return an empty list ‘() for Nothing and a non-empty list containing the value ‘(x) for Just. Those two return values are easy to distinguish by the null? and pair? predicates, and since both are lists there is no issue of type mis-match as there would be if you returned say an integer for the value x or the boolean #f for Nothing.
Paul and Graham: I think for both of you it would be quicker to build your list of powers of two by repeatedly multiplying by two, as the suggested solution does, rather than exponentiating at each step.
Indeed it is slower to use 2**i for each step. Here a version where the string representations for all powers arecalculated first (costs a little time).
Fair enough!
I like the Scheme idiom and the Python version of returning -1 (or even throwing an exception,
if the setting is right). I’m just recently somewhat enamored with Haskell’s types, though; they
make the meaning of the code clear to me in a way that these idioms don’t, I guess.
//Using Java
Double[] pow = new Double[1000];
private void calculatePOW()
{
for(int i=0;i<1000;i++)
pow[i] = Math.pow(2,i);
}
public int searchinPOW(int x)
{
int index = -1;
for(int i=0;i<pow.length;i++)
{
double power = pow[i];
if(String.valueOf(power).contains(String.valueOf(x)))
{
index = i;
break;
}
}
return index;
}
Forgive my formatting !!
In Racket:
Here is a C# solution with caching.
I used a suffix trie to store the number sequences (without the compression the your usual suffix trie has).
The numbers are stored implicitly as indexes in the children.
I also annotated the minimum base-two exponent that can reach each node in the suffix tree.
So if a digit sequence has been seen before, its O(n) performance (n = amount of digits).