That was my original version, then I thought writing two functions might confuse people so I changed it into this. It's just for the sake of demonstration and better readability.π€But you were right, it is a bad habit to extend a native prototype.
How would you come to this concept as I have no idea of this concept to far extend. Have you done these type of quest. or this(concept of using modulus) is the only way of solving this problem?
Well, I imagine that there are other ways to solve it. I came to it when I realised that it wasn't a coding problem as much as a maths problem. There are two key things that we know:
For natural numbers, doubling a number always makes it bigger than adding one (except when the number is 1, then it doesn't matter). So adding one is only needed to reach numbers with odd divisors
The number that we need to reach
Therefore, since we know the number that we need to reach, it is a lot quicker to work backwards (from the number we need to reach) than to make guesses from number 1. Starting from the end, every time we get to an odd number we subtract 1 (the backward of adding one) and every time we get to an even number we divide by 2 (the backward of multiplying by two).
Since we are dividing by 2 every time we can, that'll ensure that we're always taking as few steps as possible.
Since the amount of steps is the same whether we go 1->n or n->1, working backwards will give us the same result.
I wrote two versions of this. The first one I wrote was an exhaustive search. Then I read some answers here and wanted to write up the solution @savagepixie
had and compared them. They matched on all the numbers I tested on (up to 200 in the test case).
At first I wasn't convinced that the 'simpler' solution of counting down was gonna work, but I was definitely wrong! It performs way better than my exhaustive search and seems to be just as accurate
pubfnshortest_step_exhaustive_recurse(num:u64)->Option<u64>{fnrecursive_helper(cur:u64,goal:u64)->Option<u64>{ifcur==goal{Some(0)}elseifcur>goal{None}else{[cur+1,cur*2].iter().filter_map(|next_try|recursive_helper(*next_try,goal)).map(|attempt|attempt+1).min()}}recursive_helper(1,num)}pubfnshortest_step_count_down(num:u64)->Option<u64>{ifnum==0{None}elseifnum==1{Some(0)}elseifnum%2==0{Some(1+shortest_step_count_down(num/2)?)}else{Some(1+shortest_step_count_down(num-1)?)}}#[cfg(test)]modtests{usecrate::*;#[test]fnall_algos_work_for_three(){assert_eq!(shortest_step_exhaustive_recurse(3),Some(2));assert_eq!(shortest_step_count_down(3),Some(2));}#[test]fnall_algos_work_for_twelve(){assert_eq!(shortest_step_exhaustive_recurse(12),Some(4));assert_eq!(shortest_step_count_down(12),Some(4));}#[test]fnall_algos_match_up_to_200(){foriin0..200{assert_eq!(shortest_step_count_down(i),shortest_step_exhaustive_recurse(i),"Algos don't match for {}",i);}}}
19 yo student *and* a full-time developer.
Building with Rails currently, exploring new frontiers.
I enjoy functional programming, Linux, FOSS, refactoring and mentoring :)
Coding since 11yo, that makes it over 30 years now ~~~
Have a PhD in Comp Sci ~~~
Love to go on bike tours ~~~
I try to stay as generalist as I can in this crazy wide place coding is at now.
// Wow,.. fancy :|step=n=>(n&~1)>>((~n)&1)// note that they're ~'s, not -'s// Count how many times we need to iterate step until it hits 0countSteps=n=>{if(n<=0||Math.floor(n)!==n)thrownewError(`countSteps only accepts positive integers, ${n} was passed`);letcount=0;while(n=step(n))count++;returncount;}
If you convert the number to binary, the steps are exactly
(
number of 1s- 1) * 2 +number of 0sThis way we donβt need loops or recursion.
I was about to submit something like that, so have my applause instead ππ
A little more thinking on the problem can really simplify the solution!
(On a side note, I wouldn't extend a native prototype, but that's out of context now π )
That was my original version, then I thought writing two functions might confuse people so I changed it into this. It's just for the sake of demonstration and better readability.π€But you were right, it is a bad habit to extend a native prototype.
Wow this is brilliant! Nice job!
There is probably a better way that doesn't use loops, but these are my initial thoughts:
(using JavaScript)
That was my idea as well.
How would you come to this concept as I have no idea of this concept to far extend. Have you done these type of quest. or this(concept of using modulus) is the only way of solving this problem?
Well, I imagine that there are other ways to solve it. I came to it when I realised that it wasn't a coding problem as much as a maths problem. There are two key things that we know:
Therefore, since we know the number that we need to reach, it is a lot quicker to work backwards (from the number we need to reach) than to make guesses from number 1. Starting from the end, every time we get to an odd number we subtract 1 (the backward of adding one) and every time we get to an even number we divide by 2 (the backward of multiplying by two).
Since we are dividing by 2 every time we can, that'll ensure that we're always taking as few steps as possible.
Since the amount of steps is the same whether we go
1->norn->1, working backwards will give us the same result.Here's some recursion. I think it will work, but I'm not sure since I'm on my phone, I'll test it when I get home.
I wrote two versions of this. The first one I wrote was an exhaustive search. Then I read some answers here and wanted to write up the solution @savagepixie had and compared them. They matched on all the numbers I tested on (up to 200 in the test case).
At first I wasn't convinced that the 'simpler' solution of counting down was gonna work, but I was definitely wrong! It performs way better than my exhaustive search and seems to be just as accurate
Elixir
First time doing anything on Elixir. It was fun :)
Live demo on Paiza.io.
Elixir:
Recursive thinking is fun :)
JS using a bit of bitwise math
(couple of edits to make it cleaner)
Ruby:
:)
Here is the simple solution with Python:
And here goes an ugly one!