I have numbers as x,y,z, and w.
I am trying to create max possible time in 24 hours format.
Example:
My approach is to sort the all numbers. Then for hours check the number less than equal 2, then for next digit in hour, check number less then equal to 4,
and so on for minutes also. (0-60 minutes)
Is any other efficient approach than bruteforce solution?
Simple approach would be to create all possible combinations of all the number from four digits. Then sort and pick out all the values less than 2359 (Max time allowed). After this you start with the max number and just validate if it is a correct time if not check the next biggest number.
Basically what you can do is instead of all permutations you create conditions for each value in the array. For example if we have a 2 we know the hour should be 2 for our ten spot but our ones spot for the hour can only be 3 at that point. If we have a 1 then we know our one spot for the hour can be 9. We know our minute ten spot is 5 and our max minute one spot is 9. createTime shows these conditions. The findMaxSpecific returns -1 if it isn't able to find a valid number in the given array. That way we know the time is invalid if we ever get an array returned by createTime with -1's in it. See example output.
public static int[] createTime(int[] numbers)
{
int[] time = new int[4];
time[0] = findMaxSpecific(numbers, 2);
time[1] = time[0] == 2 ? findMaxSpecific(numbers, 3) : findMaxSpecific(numbers, 9);
time[2] = findMaxSpecific(numbers, 5);
time[3] = findMaxSpecific(numbers, 9);
return time;
}
public static int findMaxSpecific(int[] arr, int valToFind)
{
if(arr.length != 4)
return -1;
int numToFind = -1;
int indexToRemove = -1;
for(int i = 0; i < arr.length; i++)
{
if(arr[i] <= valToFind)
{
if(arr[i] > numToFind)
{
numToFind = arr[i];
indexToRemove = i;
}
}
}
if(indexToRemove == -1)
return -1;
arr[indexToRemove] = -1;
return numToFind;
}
At the end of all this is if any value comes back as -1 we know we have an invalid time we were given
Example
int[] time = new int[4];
int[] numbers = {1,2,3,4};
time = createTime(numbers);
System.out.println(time[0] + "" + time[1] + ":" + time[2] + "" + time[3]);
int[] numbers2 = {0,9,7,1};
time = new int[4];
time = createTime(numbers2);
System.out.println(time[0] + "" + time[1] + ":" + time[2] + "" + time[3]);
int[] numbers3 = {9,9,9,9};
time = new int[4];
time = createTime(numbers3);
System.out.println(time[0] + "" + time[1] + ":" + time[2] + "" + time[3]);
Output is
23:41
19:07
-19:-19 //invalid numbers
For input 1 2 9 9, the only possibility is 19:29, but what you describe picks the two first and gets 21:99, an invalid time.
Unless this is indeed a bottleneck and not a programming exercise, the most straightforward solution is to try all possible permutations of the digits, for each one, check whether it constitutes a valid time, and take the lexicographically maximal valid string.
The point is, there are fast solutions and there are correct solutions.
Here, the fast solution is tricky, so if program running time is not critical, do consider the possibility to pick the slower but more obvious solution.
This will perhaps give you, as a programmer, more time to tackle the other problems where running time does matter.
Sadly, Java does not seem to provide a builtin nextPermutation method, but Stackoverflow sure does.
input = (1,2,3,4)
ans = None
for hour in range(0, 24):
for minute in range(0,60):
if possible(hour, minute, input):
ans = "%s:%s" % (hour, minute)
here your possible function should count the digits in hour, minute and input and make sure they equate.
I would have a method you can give a predicate which extract the highest value which matches the predicate.
e.g.
public static int highest(List<Integer> values, Predicate<Integer> test) {
Integer max = values.stream()
.filter(test)
.max(Comparator.natrualOrder())
.orElseThrow(() -> new InvalidStateException());
values.remove(max);
return max;
}
int digit1 = highest(list, i -> i < 3);
int digit3 = highest(list, i -> i < 6);
int digit2 = highest(list, i -> digit1 < 2 || i < 4);
int digit4 = highest(list, i -> true);
Interesting problem. Seems a little bit more complex than it appears. Here is a python script for the problem.
def getmin(num): # check if two digits are valid for minutes
min = -1
sum = num[0] * 10 + num[1]
if sum < 60:
min = sum
sum = num[1] * 10 + num[0]
if sum < 60 and min < sum:
min = sum
return min
def maxtime(num):
hour = -1
min = -1
h1 = 0
h2 = 0
for i in range(4):
for j in range(4): # these two loops are to get maxi hour, if possible
if i != j:
sum = num[i] * 10 + num[j]
if hour < sum and sum < 24:
c = num[:] # get a copy of input digits
if i > j: # delete numbers used in hour
del c[i]
del c[j]
else:
del c[j]
del c[i]
if getmin(c) > -1:
h1 = i
h2 = j
hour = sum
if hour > -1:
if h2 > h1: # delete numbers used in hour
del num[h2]
del num[h1]
else:
del num[h1]
del num[h2]
min = getmin(num)
if min > -1:
print(str(hour) + ':' + str(min))
if hour < 0 or min < 0:
print("no solution")
maxtime([4, 8, 1, 9])
maxtime([7, 3, 4, 2])
maxtime([9, 2, 2, 5])
maxtime([9, 2, 7, 3])
#19:48
#23:47
#22:59
#no solution
Related
There are n stairs, a person standing at the bottom wants to reach the top. The person can climb either 1 stair or 2 stairs at a time.
Now I want to find the minimum number of steps needed that are divisible by given number m.
Here is the java program which I created using this as a reference, which is used to print the possible steps:
public static void main(String args[]) {
int n = 10, m = 2;
List<Integer> vals = new ArrayList<>();
Set<String> set = new TreeSet<>(Comparator.reverseOrder());
ClimbWays(n, 0, new int[n], vals, set);
set.forEach(a -> {
System.out.println(a + " : " + a.length());
});
}
public static void ClimbWays(int n, int currentIndex, int[] currectClimb, List<Integer> vals, Set<String> set) {
if (n < 0)
return;
if (n == 0) {
vals.add(currentIndex);
int last = 0;
StringBuilder sb = new StringBuilder();
for (int i = currentIndex - 1; i >= 0; i--) {
int current = currectClimb[i];
int res = current - last;
last = current;
sb.append(res);
}
String s = sb.toString();
char[] c = s.toCharArray();
Arrays.sort(c);
s = new String(c);
set.add(s);
return;
}
currectClimb[currentIndex] = n;
ClimbWays(n - 1, currentIndex + 1, currectClimb, vals, set);
ClimbWays(n - 2, currentIndex + 1, currectClimb, vals, set);
}
Output of the program is :
22222 : 5
112222 : 6
1111222 : 7
11111122 : 8
111111112 : 9
1111111111 : 10
Now for steps 10 if I want to get minimum steps divisible by m = 2, then the solution is 112222 which has 6 as the number of steps needed.
This program basically finds all possible pairs then add them to tree set. Next, I can loop through this set and get the minimum element divisible by given input m.
Is there a better approach to do this?
Since the person can climb a maximum of 2 steps at a time, the minimum number of steps to climb n stairs is
x = n/2 if n is even
x = n/2 + 1 if n is odd
Now you need to find the minimum number of steps to climb n stairs which is divisible by m. Meaning you need to find a number immediate next to x which is divisible by m.
if x%m == 0 then x is your answer
if x%m != 0 then ((x/m) + 1) * m is your answer.
Now speaking of your example
For n = 10,
x = n/2 = 5,
x%m = 5 % 2 = 1 != 0
Thus ans = ((5/2) + 1) * 2 = 6
Input
1: array size (1 to 10^5)
2: Number to take average (1 to 10^3)
3: elements in array (1 to 10^5) Non sorted, any order is possible
Output: Maximum possible average of any sub-array.
Eg:
5 3
1 2 3 4 5
o/p = 5
5 4
1 2 3 4 5
o/p = 3
for first example seq will be sum[0,4]=15 and its average with 3 will be 5.
for second example seq will be sum[2,4]=12 and its average with 4 will be 3.
I already have below given solution of o(n^2) but its not working for large inputs.
long max = 0;
for( int m = 0; m < people; m++ )
{
long sum = 0;
for( int n = m; n < people; n++ )
{
sum = sum + chocolateArray[n];
if( sum % boxes == 0 )
{
if( ( sum / boxes ) > max )
{
max = sum / boxes;
}
}
}
}
System.out.println( max );
where people is array size, boxes is average number and chocolateArray is original array.
Please provide efficient solution. I thought to take it through dynamic programming but creating two dimensional array of 10^5 size is causing outofmemory issue.
Since all numbers are positive, the only effective constraint is the divisibility. So the question is asking for the maximum subarray sum that is divisible by m, the number of boxes.
This can be done by creating an array of the cumulative sum, modulo m, then finding two places with the same numbers, as far apart as possible. Since there are at most m values, we can simply store the minimum and maximum index of every possible residue, then take the one with the maximum subarray sum. The code below does that.
cumsum = int[people+1];
minPos = int[boxes];
maxPos = int[boxes];
Arrays.fill(minPos, -1);
Arrays.fill(maxPos, -1);
int residue = 0;
for(int i=0; i<people; i++){
cumsum[i+1] = cumsum[i] + chocolateArray[i]; // For simplicity the array length is 1 longer
residue = cumsum[i+1] % boxes;
if(minPos[residue] == -1) minPos[residue] = i;
maxPos[residue] = i;
}
int max = 0;
for(int i=0; i<boxes; i++){
int sum = cumsum[maxPos[i]+1] - cumsum[minPos[i]+1];
if(sum > max){
max = sum;
}
}
System.out.println(max/boxes);
For example:
People = 5
Boxes = 4
Array = [1, 2, 3, 4, 5]
Cumulative = [1, 3, 6, 10, 15]
Residue = [1, 3, 2, 2, 3]
MinMaxPos[0] = (-1, -1) -> sum = 0 -> avg = 0
MinMaxPos[1] = (0, 0) -> sum = 0 -> avg = 0
MinMaxPos[2] = (2, 3) -> sum = 4 -> avg = 1
MinMaxPos[3] = (1, 4) -> sum = 12 -> avg = 3
Building on #justhalf's brilliant solution. we will be able to do this using a single pass and only a single array
let dp[boxes] be a array of length boxes where dp[i] will hold the minimum sum so far which has i = current_sum % boxes
Since all the numbers are positive number we can store only the first occurrence of a the particular residue since the next time this residue occurs it will be greater that the previous sum.
At each iteration we check if a particular residue has been already found. If yes then then we subtract the current_sum with the previous sum of that residue.
Else we update the sum for the residue and move.
int maxSubArrayAverage(vector<int> people, int boxes)
{
vector<int> dp(boxes, -1);
int max_sum = 0, current_sum = 0;
dp[0] = 0; // if residue is 0 entire current_sum is the choice
for(int i=0; i < people.size(); ++i)
{
current_sum += people[i];
int residue = current_sum % boxes;
if(dp[residue] == -1) // update for the first time
{
dp[residue] = current_sum;
}
else
{
max_sum= max(max_sum, current_sum - dp[residue]);
// cout << i << ' ' << current_sum << ' ' << residue << ' ' << max_average << endl;
}
}
// copy(dp.begin(), dp.end(), ostream_iterator<int>(cout, " "));
// cout << endl;
return max_sum/boxes;
}
My problem is as follows; for number N, I need to find out what is the largest value I can count to, when each digit can be used N times.
For example if N = 5, the largest value is 12, since at that point the digit 1 has been used 5 times.
My original approach was to simply iterate through all numbers and keep a tally of how many times each digit has been used so far. This is obviously very inefficient when N is large, so am looking for advice on what would be a smarter (and more efficient) way to achieve this.
public class Counter {
private static Hashtable<Integer, Integer> numbers;
public static void main(String[] args){
Counter c = new Counter();
c.run(9);
}
public Counter() {
numbers = new Hashtable<Integer, Integer>();
numbers.put(0, 0);
numbers.put(1, 0);
numbers.put(2, 0);
numbers.put(3, 0);
numbers.put(4, 0);
numbers.put(5, 0);
numbers.put(6, 0);
numbers.put(7, 0);
numbers.put(8, 0);
numbers.put(9, 0);
}
public static void run(int maxRepeat) {
int keeper = 0;
for(int maxFound = 0; maxFound <= maxRepeat; maxFound++) {
keeper++;
for (int i = 0; i < Integer.toString(keeper).length(); i++) {
int a = Integer.toString(keeper).charAt(i);
//here update the tally for appropriate digit and check if max repeats is reached
}
}
System.out.println(keeper);
}
}
For starters, rather than backing your Counter with a Hashtable, use an int[] instead. When you know exactly how many elements your map has to have, and especially when the keys are numbers, an array is perfect.
That being said, I think the most effective speedup is likely to come from better math, not better algorithms. With some experimentation (or it may be obvious), you'll notice that 1 is always the first digit to be used a given number of times. So given N, if you can find which number is the first to use the digit 1 N+1 times, you know your answer is the number right before that. This would let you solve the problem without actually having to count that high.
Now, let's look at how many 1's are used counting up to various numbers. Throughout this post I will use n to designate a number when we are trying to figure out how many 1's are used to count up to a number, whereas capital N designates how many 1's are used to count up to something.
One digit numbers
Starting with the single-digit numbers:
1: 1
2: 1
...
9: 1
Clearly the number of 1's required to count up to a one-digit number is... 1. Well, actually we forgot one:
0: 0
That will be important later. So we should say this: the number of 1's required to count up to a one-digit number X is X > 0 ? 1 : 0. Let's define a mathematical function f(n) that will represent "number of 1's required to count up to n". Then
f(X) = X > 0 ? 1 : 0
Two-digit numbers
For two-digit numbers, there are two types. For numbers of the form 1X,
10: 2
11: 4
12: 5
...
19: 12
You can think of it like this: counting up to 1X requires a number of 1's equal to
f(9) (from counting up to 9) plus
1 (from 10) plus
X (from the first digits of 11-1X inclusive, if X > 0) plus
however many 1's were required to count up to X
Or mathematically,
f(1X) = f(9) + 1 + X + f(X)
Then there are the two-digit numbers higher than 19:
21: 13
31: 14
...
91: 20
The number of 1's required to count to a two-digit number YX with Y > 1 is
f(19) (from counting up to 19) plus
f(9) * (Y - 2) (from the 1's in numbers 20 through (Y-1)9 inclusive - like if Y = 5, I mean the 1's in 20-49, which come from 21, 31, 41) plus
however many 1's were required to count up to X
Or mathematically, for Y > 1,
f(YX) = f(19) + f(9) * (Y - 2) + f(X)
= f(9) + 1 + 9 + f(9) + f(9) * (Y - 2) + f(X)
= 10 + f(9) * Y + f(X)
Three-digit numbers
Once you get into three-digit numbers, you can kind of extend the pattern. For any three-digit number of the form 1YX (and now Y can be anything), the total count of 1's from counting up to that number will be
f(99) (from counting up to 99) plus
1 (from 100) plus
10 * Y + X (from the first digits of 101-1YX inclusive) plus
however many 1's were required to count up to YX in two-digit numbers
so
f(1YX) = f(99) + 1 + YX + f(YX)
Note the parallel to f(1X). Continuing the logic to more digits, the pattern, for numbers which start with 1, is
f(1[m-digits]) = f(10^m - 1) + 1 + [m-digits] + f([m-digits])
with [m-digits] representing a sequence of digits of length m.
Now, for three-digit numbers ZYX that don't start with 1, i.e. Z > 1, the number of 1's required to count up to them is
f(199) (from counting up to 199) plus
f(99) * (Z - 2) (from the 1's in 200-(Z-1)99 inclusive) plus
however many 1's were required to count up to YX
so
f(ZYX) = f(199) + f(99) * (Z - 2) + f(YX)
= f(99) + 1 + 99 + f(99) + f(99) * (Z - 2) + f(YX)
= 100 + f(99) * Z + f(YX)
And the pattern for numbers that don't start with 1 now seems to be clear:
f(Z[m-digits]) = 10^m + f(10^m - 1) * Z + f([m-digits])
General case
We can combine the last result with the formula for numbers that do start with 1. You should be able to verify that the following formula is equivalent to the appropriate case given above for all digits Z 1-9, and that it does the right thing when Z == 0:
f(Z[m-digits]) = f(10^m - 1) * Z + f([m-digits])
+ (Z > 1) ? 10^m : Z * ([m-digits] + 1)
And for numbers of the form 10^m - 1, like 99, 999, etc. you can directly evaluate the function:
f(10^m - 1) = m * 10^(m-1)
because the digit 1 is going to be used 10^(m-1) times in each of the m digits - for example, when counting up to 999, there will be 100 1's used in the hundreds' place, 100 1's used in the tens' place, and 100 1's used in the ones' place. So this becomes
f(Z[m-digits]) = Z * m * 10^(m-1) + f([m-digits])
+ (Z > 1) ? 10^m : Z * ([m-digits] + 1)
You can tinker with the exact expression, but I think this is pretty close to as good as it gets, for this particular approach anyway. What you have here is a recursion relation that allows you to evaluate f(n), the number of 1's required to count up to n, by stripping off a leading digit at each step. Its time complexity is logarithmic in n.
Implementation
Implementing this function is straightforward given the last formula above. You can technically get away with one base case in the recursion: the empty string, i.e. define f("") to be 0. But it will save you a few calls to also handle single digits as well as numbers of the form 10^m - 1. Here's how I'd do it, omitting a bit of argument validation:
private static Pattern nines = Pattern.compile("9+");
/** Return 10^m for m=0,1,...,18 */
private long pow10(int m) {
// implement with either pow(10, m) or a switch statement
}
public long f(String n) {
int Z = Integer.parseInt(n.substring(0, 1));
int nlen = n.length();
if (nlen == 1) {
return Z > 0 ? 1 : 0;
}
if (nines.matcher(n).matches()) {
return nlen * pow10(nlen - 1);
}
String m_digits = n.substring(1);
int m = nlen - 1;
return Z * m * pow10(m - 1) + f_impl(m_digits)
+ (Z > 1 ? pow10(m) : Z * (Long.parseLong(m_digits) + 1));
}
Inverting
This algorithm solves the inverse of the the question you're asking: that is, it figures out how many times a digit is used counting up to n, whereas you want to know which n you can reach with a given number N of digits (i.e. 1's). So, as I mentioned back in the beginning, you're looking for the first n for which f(n+1) > N.
The most straightforward way to do this is to just start counting up from n = 0 and see when you exceed N.
public long howHigh(long N) {
long n = 0;
while (f(n+1) <= N) { n++; }
return n;
}
But of course that's no better (actually probably worse) than accumulating counts in an array. The whole point of having f is that you don't have to test every number; you can jump up by large intervals until you find an n such that f(n+1) > N, and then narrow down your search using the jumps. A reasonably simple method I'd recommend is exponential search to put an upper bound on the result, followed by a binary search to narrow it down:
public long howHigh(long N) {
long upper = 1;
while (f(upper + 1) <= N) {
upper *= 2;
}
long lower = upper / 2, mid = -1;
while (lower < upper) {
mid = (lower + upper) / 2;
if (f(mid + 1) > N) {
upper = mid;
}
else {
lower = mid + 1;
}
}
return lower;
}
Since the implementation of f from above is O(log(n)) and exponential+binary search is also O(log(n)), the final algorithm should be something like O(log^2(n)), and I think the relation between N and n is linear enough that you could consider it O(log^2(N)) too. If you search in log space and judiciously cache computed values of the function, it might be possible to bring it down to roughly O(log(N)). A variant that might provide a significant speedup is sticking in a round of interpolation search after determining the upper bound, but that's tricky to code properly. Fully optimizing the search algorithm is probably a matter for another question though.
This should be more efficient. Use integer array of size 10 to keep the count of digits.
public static int getMaxNumber(int N) {
int[] counts = new int[10];
int number = 0;
boolean limitReached = false;
while (!limitReached) {
number++;
char[] digits = Integer.toString(number).toCharArray();
for (char digit : digits) {
int count = counts[digit - '0'];
count++;
counts[digit - '0'] = count;
if (count >= N) {
limitReached = true;
}
}
}
return number;
}
UPDATE 1: As #Modus Tollens mentioned initial code has a bug. When N = 3 it returns 11, but there are four 1s between 1 and 11. The fix is to check if limit is breached count[i] > N on given number, previous number should be return. But if for some i count[i] == N for other j count[j] <= N, the actual number should be returned.
Please see corresponding code below:
public static int getMaxNumber(int N) {
int[] counts = new int[10];
int number = 0;
while (true) {
number++;
char[] digits = Integer.toString(number).toCharArray();
boolean limitReached = false;
for (char digit : digits) {
int count = counts[digit - '0'];
count++;
counts[digit - '0'] = count;
if (count == N) {
//we should break loop if some count[i] equals to N
limitReached = true;
} else if (count > N) {
//previous number should be returned immediately
//, if current number gives more unique digits than N
return number - 1;
}
}
if (limitReached) {
return number;
}
}
}
UPDATE 2: As #David Z and #Modus Tollens mentioned, in case if N=13, 30 should be returned, ie, algo stops when N is breached but not reached. If this is initial requirement, the code will be even simpler:
public static int getMaxNumber(int N) {
int[] counts = new int[10];
int number = 0;
while (true) {
number++;
char[] digits = Integer.toString(number).toCharArray();
for (char digit : digits) {
int count = counts[digit - '0'];
count++;
counts[digit - '0'] = count;
if (count > N) {
return number - 1;
}
}
}
}
I am writing a program to print out a user inputed integer into binary form.
When I run it and input, say the number 5, it crashes and gives me the error:
java.lang.ArrayIndexOutOfBoundsException: 30
at PrintBinaryDigitsFixed.main(PrintBinaryDigitsFixed.java:27)
i.e the line "digits[counter] = number % 2;"
Why am I getting an out of bounds exception? It should assign the remainder to the first element then move on to the second shouldn't it?
I feel like I'm making a glaringly obvious mistake but I can't tell what it is
final int MIN = 0;
final int MAX = (int) (Math.pow(2, 30) - 1);
int[] digits = new int[30]; //array to hold the digits
int number = readInput
("Enter an integer from " + MIN + " to " + MAX, MIN, MAX);
int counter = 0;
int modNumber = 2;
while(modNumber / 2 != 0)
{
digits[counter] = number % 2;
modNumber = number / 2;
counter++;
}
System.out.print(number + " in binary form is ");
listBackwardsFrom(digits, counter);
Thanks
You never change number in your loop, and you assign modNumber = number / 2 in the loop, so from the second iteration onward modNumber is a constant (for most of the first iteration it's 2, but then you assign number / 2 to it); if you reach that point at all, you'll stay there. So the loop continues until counter reaches 30, at which point digits[counter] throws the exception.
I am trying to solve a simple DP problem:
Given a positive integer n, you can perform any one of the following 3 steps.
1) Subtract 1 from it.
2) If it is divisible by 2, divide by 2.
3) If it is divisible by 3, divide by 3.
Please find the minimum number of steps that takes n to 1 and print out the steps. If there are multiple solutions to achieve the goal in the same number of steps, please print out all these solutions. (if it is hard, at least print out one of these solutions).
Getting the minimum number of steps is not that hard. Simply apply a bottom up DP solution like this:
public int getMinSteps(int n) {
int[] dp = new int[n+1];
int i;
dp[1] = 0;
for( i = 2 ; i < = n ; i ++ ) {
dp[i] = 1 + dp[i-1];
if(i%2==0) dp[i] = min( dp[i] , 1+ dp[i/2] );
if(i%3==0) dp[i] = min( dp[i] , 1+ dp[i/3] );
}
return dp[n];
}
However, I was not able to solve the print path part. In a high level, I think I need to stop the "action" at every level a minimum is determined?
Hope I can get some good suggestion or solution here.
thanks!
Just get another field to store the optimal step, i.e. -1, /2, or /3, if it is optimal to get the minimum path, possibly just using 1, 2, 3 as indicators.
For example, you are comparing a = 1 + dp[i-1], b = 1 + dp[i/2], c = 1 + dp[i/3]. If a is minimum, then you know you should -1 for the number. Store the step as 1. Later, you just jump to the field for i-1 to find the next step until you reach the start point, i.e. 1.
Update:
If you want to print all the paths, you have to store all the optimal steps, and print all the combinations.
In details, you can use three boolean fields for -1, /2, /3 to store if any optimal path goes through a certain number. After that, you can print all the combinations recursively, like traversing a tree.
int[] dp; // for minimum steps
bool[] gominus1;
bool[] godivideby2;
bool[] godivideby3;
List<Integer> steps;
PrintAllPath(int n) {
if(n == 1) {
// print steps
return;
}
steps.push_back(n);
if(gominus1[n]) {
PrintAllPath(n - 1);
}
if(godivideby2[n]) {
PrintAllPath(n / 2);
}
if(govidivideby3[n]) {
PrintAllPath(n / 3);
}
steps.pop_back();
}
Here is How you can retrieve the path:
public static int getMinSteps(int n) {
int[] dp = new int[n + 1];
String[] path = new String[n+1];
int i;
dp[1] = 0;
path[1] = "end";
for (i = 2; i <= n; i++) {
dp[i] = 1 + dp[i - 1];
if (i % 2 == 0) {
if(dp[i] < 1 + dp[i/2]){
path[i] = "sub 1," + path[i-1];
}
else {
path[i] = "div by 2," + path[i/2];
}
dp[i] = min(dp[i], 1 + dp[i / 2]);
}
if (i % 3 == 0) {
if(dp[i] < 1 + dp[i/3]){
path[i] = "sub 1," + path[i-1];
}
else {
path[i] = "div by 3," + path[i/3];
}
dp[i] = min(dp[i], 1 + dp[i / 3]);
}
if( i % 3 != 0 && i % 2 != 0) {
path[i] = "sub 1," + path[i-1];
}
}
System.out.println("number of steps = "+dp[n]+",path = "+path[n]);
return dp[n];
}
This is to print single path. To print all the path you need to track all the minimum possible ways to dp[i]. So you need a two dimensional array of String to store them.