I was recently asked this in an interview for a front-end position and I came up with something like the code below, which seems to work but is clunky. (Number.toString()
was not allowed.)
function convertBinary(number) {
var n = 0;
var binaryArr = [];
var difference = Math.pow(2, n);
//find out how many digits are needed
while (difference <= number){
n++;
difference = Math.pow(2, n);
binaryArr.push(0);
}
n--;
while(number > 0) {
if (Math.pow(2, n) <= number) {
binaryArr[n] = 1;
number-= Math.pow(2, n);
}
n--;
}
return binaryArr.reverse().join("") * 1
}
Also I was asked what the Big(o) of this was but had a hard time figuring it out— what is the time complexity of JavaScript reverse
?
2 Answers 2
Strictly speaking, the number
parameter isn't decimal; it's just an abstract number. (This is more a criticism of the terminology in your question title than of your code.) On the other hand, it is very weird that you coerce the result into a number (101010
) rather than returning it as a string ('101010'
).
The implementation strategy, using Math.pow(..., 2)
, strikes me as extravagant. You should be able to do this more efficiently using just arithmetic:
function convertBinary(number) {
var binaryArr = [];
for (; number; number /= 2) {
binaryArr.push(number % 2);
}
return binaryArr.reverse().join('');
}
... or the same thing using bitwise operations:
function convertBinary(number) {
var binaryArr = [];
for (; number; number >>= 1) {
binaryArr.push(number & 1);
}
return binaryArr.reverse().join('');
}
-
\$\begingroup\$ test of programming skill, wasn't allowed to use toString. Are binary numbers usually returned as strings instead of numbers? Why is that the case? (I also don't really know how to use bit shifting) \$\endgroup\$WinchenzoMagnifico– WinchenzoMagnifico2016年03月05日 00:10:07 +00:00Commented Mar 5, 2016 at 0:10
-
\$\begingroup\$ The number
101010
would mean one hundred one thousand ten; the string'101010
' would be a more suitable representation of forty-two in base 2, the same way'42'
would be a suitable base-10 representation. Put another way: if the interviewer asked you to convert a number to base 16, what would you return? \$\endgroup\$200_success– 200_success2016年03月05日 01:36:22 +00:00Commented Mar 5, 2016 at 1:36 -
\$\begingroup\$ Cool solution! Without the array reverse:
a=''; for(;n;n>>=1) { a = (n & 1) + a; }
\$\endgroup\$Zack Burt– Zack Burt2020年01月02日 02:52:16 +00:00Commented Jan 2, 2020 at 2:52
Also I was asked what the Big(o) of this was but had a hard time figuring it out— what is the time complexity of JavaScript reverse?
Now, I don't know much about Big O notation, but I'll give you my two cents about this issue.
First off, I don't think that the reverse()
is actually part of the complexity. Considering this is a built-in function and all you do is simply call it, it can be considered \$O(1)\$.
However, again, I don't think that is actually part of the time complexity; when the interviewer asked that, he/she was most likely referring to your algorithm.
To find the complexity of your algorithm, think of it like this: this function you have written is a function of number
; in Big O terms, number
would be your n
.
Now, basically, all you need to do is find how many "iterations" (not the real thing, but works in this case) your function does based on it's input. To find that, you need to look here:
while (difference <= number){
and here:
while(number > 0) {
Both of these loops involve the only argument number
(n
) and will run a certain amount of times based on this argument. Looking at these they both run the range of
0 to
number
, only on powers of 2 in this range.
For example, if number
was 5000, then these would be the numbers, then you traverse:
1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096
both times (the first loop you go left to right, the second one you go right to left).
If you look further into this, you might be able to find a proper Big O notation to represent this.
Power (look-up) Table!
Looking over your algorithm, I see that you are using Math.pow
a lot. While this is a nice method and it is helpful, it can be very inefficient (especially if used too many times).
Focusing only on n
, your algorithm does this:
- Set
n
to 0 - Increment
n
to a limit, calculatingMath.pow
each increment. - Decrement
n
back down to zero, calculatingMath.pow
twice for each decrement (except for the first).
So, if the limit ends up being 10 in this case, you would have called Math.pow
28 times.
A way to speed this up would be to create an array and store all the Math.pow
s in it when you are first incrementing up to the limit. Then, when you are decrementing, simply reference the table for the value. This would reduce those 28 calls down to only 10.
In your first loop:
while (difference <= number){
n++;
powArr[n] = difference = Math.pow(2, n);
binaryArr.push(0);
}
Then, in your second loop:
while(number > 0) {
var pow = powArray[n];
if (pow <= number) {
binaryArr[n] = 1;
number -= pow
}
n--;
}
Note: I added in a pow
variable so you don't have to access the array twice.
Now, your code doesn't have to call this expensive Math.pow
as often, overall increasing the speed of your code.
-
1\$\begingroup\$
Considering this is a built-in function and all you do is simply call it, it can be considered O(1)
. This sentence is untrue. Consider the simpleArray#forEach
method - its complexity is obviously O(n), but it's a builtin.Array#reverse
has the same O(n) complexity, there are no shortcuts here made possible by running native code. \$\endgroup\$Tibos– Tibos2018年05月21日 16:33:16 +00:00Commented May 21, 2018 at 16:33
Explore related questions
See similar questions with these tags.