It can be regarded as search or DP problem (yes in essence they are both related to state transition), the key point is to define search state condition, suppose n
is positive, here we define f[i] = inf, inf is a really large integer
means number i
is not reachable, f[i] = k, k >= 0
means number i
can be reached in at least k
steps.
If n
is not so large, we can use an array to store least steps for each number from 1 to n. The initial is that f[1] = 0
and f[i] = inf, 2 <= i <= n
. If we need to output how we get the target(ex, output of 5 is 1 2 4 5
), we can use another array pre
to store the operations, define pre[i] = j
means number i
is produced by number j
(ex, pre[4] = 2
means number 4 is produced by number 2, because 2*2=4; pre[3] = 1
means number 3 is produced by number 1, because 1*3=3):
int inf = Integer.MAX_VALUE;
f[1] = 0;
pre[1] = -1; // pre[i] = -1 means i is the start point
for(i=2;i<=n;i++) {
f[i] = inf;
pre[i] = -1;
}
for(int i=1;i<=n;i++) { // since each number is positive so smaller number cannot be produced via larger number, no need to consider > n issue
if(f[i] == inf) {
continue;
}
if(2*i <= n && f[i] + 1 < f[2*i]) {
f[2*i] = f[i] + 1;
pre[2*i] = i; // means number 2*i is produced by number i
}
if(3*i <= n && f[i] + 1 < f[3*i]) {
f[3*i] = f[i] + 1;
pre[3*i] = i;
}
if(i+1 <= n && f[i] + 1 < f[i+1]) {
f[i+1] = f[i] + 1;
pre[i+1] = i;
}
}
The answer is f[n]
.
How to output how we get target, we use the pre
array to recover the operations:
curr = n;
pos = 0;
ans[pos] = n;
while(pre[curr] != -1) {
pos++;
ans[pos] = pre[curr];
curr = pre[curr];
}
for(int i=pos;i>=0;i--) { // reverse order to output
System.out.println(ans[i]);
}
While if n
is very large, you may need to use a priority queue to maintain state transition and a hash set to maintain least steps for each number.