I have the following problem statement:
Given a number n (1 < n < 10^9), what is the least number of mathematical operations from the set (divide n by 2, divide n by 3, subtract 1 from n) that can be used to transform the number n to 1?
I have written the following code so far in an attempt to solve the problem:
while(n!=1){
if(n%3==0 || n%2==0){
if(n%3==0){
n=n/3;
c=c+1;
}
if(n%2==0){
n=n/2;
c=c+1;
}
}
else{
n=n-1;
c=c+1;
}
}
System.out.println(c);
But I dont get the desired output. Can someone help me with it.
I think that Tristan is right—you have no way to know which operation will end up yielding the shortest path up-front, so you have to try all of them in order to get the right answer.
Typically, a brute-force solution like this would imply that the calculation will take exponential time. You start with n, then calculate up to 3 new numbers using your 3 operations. Then for each of those 3 numbers you get another 3, totaling 9. Then for each of those 9 you get another 3, totaling 27; and so on. You can see how you would quickly end up with a ridiculous number of possibilities.
However, your search space here is limited. Since all of your operations will cause the value to decrease, you will only encounter numbers from 1 to n, inclusive. This means it will take at most n operations to reach your goal of 1. There's only one shortest-length path to each number, so once you've found that path you don't need to consider any other paths you find that lead to that same number. If you keep a set of previously seen numbers, you should be able to eliminate a huge portion of your search space since you can throw out repeated results. (This is a form of Memoization.)
Here's how I would do that problem:
Set<Integer>
to contain previously seen values.Map<Integer, Integer>
to hold your active values. Each key → value entry's key would be a number in the path from n to 1
, and the value would be the number of operations it took to reach that number.0
in your active map.1
(your target):
1
→ i in your active map.There are a few things you could do to speed this up a bit more (e.g. break out of the loop immediately when you find 1
), or decrease the memory footprint (e.g. you discard sentries from the seen set if they're bigger than any of your active entries, or use a list instead of a map since all the i values for an iteration are the same), but this should be efficient enough to do what you need.
I've ported my solution to Java and posted it here:
http://ideone.com/qWt0LE
The output contains some timings. Note that the solution linked here uses a map for seen and a list for active. I store the previous number in the chain as the value for each map entry in seen, which allows me to reconstruct the chain at the end. In the output, 3 means divided by 3, 2 means divided by 2, and 1 means subtracted 1.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With