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.
Related
Given an input string of digits, split that into groups of prime numbers by maintaining the order given in the input string and each group should hold all the characters of the input string. Find the count of such groups.
Example:
11375
Ans:
3
Explanation:
The 3 combinations are [11,37,5], [11,3,7,5] and [113,7,5]
Code that I tried
public int countPossibilities(String s) {
int n = s.length();
int[] ar = new int[n + 1];
ar[0] = 1;
for (int i = 1; i < n; i++) {
int j = i - 1;
while (j >= 0 && j >= i - 3) {
if (prime(s.substring(j, i)))
ar[i] += ar[j];
j--;
}
}
return ar[n];
}
public boolean prime(String s) {
int n = Integer.parseInt(s);
if (n < 2) return false;
for (int i = 2; i * i <= n; i++)
if (n % i == 0) return false;
return true;
}
This works fine if the input string length is small.
But the length of the input string can be from 1 to 10^5. So my program fails for large strings.
Example:
1350297079989171477791892123929141605573631151125933376097791877830238462471373933362476484818693477173990672289892448124097556197582379957168911392680312103962394732707409889862447273901522659
Expected result is : 4386816
What is the right approach to solve this problem.
Here's working Python code that answers your long example.
Let dp[i] represent the number of valid combinations ending at the ith index of the input. Then for each prime suffix of length x ending at input[i], we add to dp[i] the count of valid combinations ending at dp[i-x], provided there is also a count of valid combinations recorded for dp[i-x].
# https://rosettacode.org/wiki/Sieve_of_Eratosthenes
def primes2(limit):
if limit < 2: return []
if limit < 3: return [2]
lmtbf = (limit - 3) // 2
buf = [True] * (lmtbf + 1)
for i in range((int(limit ** 0.5) - 3) // 2 + 1):
if buf[i]:
p = i + i + 3
s = p * (i + 1) + i
buf[s::p] = [False] * ((lmtbf - s) // p + 1)
return set(["2"] + [str(i + i + 3) for i, v in enumerate(buf) if v])
def f(n):
# The constant, k, limits the number
# of digits in the suffix we're
# checking for primality.
k = 6
primes = primes2(10**k)
dp = [0] * len(n) + [1]
for i in range(len(n)):
suffix = ""
for j in range(min(i + 1, k)):
suffix = n[i-j] + suffix
if suffix in primes and dp[i-j-1] > 0:
dp[i] += dp[i-j-1]
return dp[len(n) - 1]
Output:
n = "1350297079989171477791892123929141605573631151125933376097791877830238462471373933362476484818693477173990672289892448124097556197582379957168911392680312103962394732707409889862447273901522659"
print(f(n)) # 4386816
Proof of concept from my comments, but in C# (I'm an AP Comp Sci teacher that doesn't like to code in Java; go figure!):
Take the length of the input string minus 1 and call this "padLength".
Now raise 2 to the power of padLength to get the total number of
possibilities for string combinations; call this number
"numberOfCombinations". Next, count from 0 to numberOfCombinations and
convert that decimal number to a BINARY number, left padded with
zeroes out to padLength, called "binaryNumber". The binary number
represents whether or not a space should be added in-between the
digits of the original number. For instance, binary "1100" and dec
"11375" would result in "1 1 375" because 1 means put a space
in-between. This process will give you all combinations of the
original string in the different groups. Then you can extract the
numbers from the groups and see if they are primes...
Code:
private async void button1_Click(object sender, EventArgs e)
{
if (textBox1.Text.Trim().Length == 0) { return; }
textBox1.Enabled = false;
button1.Enabled = false;
textBox2.Clear();
String binary;
StringBuilder sb = new StringBuilder();
String input = textBox1.Text.Trim();
char[] digits = input.ToCharArray();
int padLength = input.Length - 1;
long combinations = (long)Math.Pow(2, padLength);
List<String> combos = new List<string>();
await Task.Run(() => {
for (long i = 0; i < combinations; i++)
{
binary = Convert.ToString(i, 2).ToString().PadLeft(padLength, '0');
char[] binaryDigits = binary.ToCharArray();
sb.Clear();
for (int s = 0; s < digits.Length; s++)
{
sb.Append(digits[s]);
if (s < (digits.Length - 1))
{
if (binaryDigits[s] == '1')
{
sb.Append(' ');
}
}
}
combos.Add(sb.ToString());
}
});
textBox2.Lines = combos.ToArray();
textBox1.Enabled = true;
button1.Enabled = true;
}
Output:
For very large inputs, you won't be able to compute the number of combinations using Math.Pow(), or any built-in methods for converting a decimal to a binary number. In those cases, you can "count manually" in binary by using a String directly and following the counting algorithm. You'd build the binary numbers using only String manipulation directly by inspecting each char to see if it is 1 or 0 and acting accordingly. You'll know you're done when you have a string of ones that has a length one less than the length of your input. It will run a lot slower than working with numbers directly.
I had an interview and I've been asked to print numbers from 1 to a 1000 digit number -
1,
2,
3,
.
.
.
.,
999999999999999999999999999999999999999999999999........
I couldn't solve it but I'm still looking for the best way to do it, because obviously, you cant use integers or floats in a case like this and because it's a job interview I couldn't use any libraries that can handle it.
Can anyone think of a good solution? preferably in Java/pseudocode.
I had an interview and I've been asked to print numbers from 1 to a 1000 digit number
I guess the kind of answer they expected you to give is:
"We need to print the numbers from 1 to 10^1000-1. Last year, $80e9 worth of processors were sold worldwide [1], even if one processor per dollar had been sold and each processor was a thousand times faster than the fastest of them all [2] and only one instruction was used to print each number and all these processors had been produced during the last 1000 years, still: 1e1000 / (80e9 - 1000 - 8.4e9 - 1000) > 1e973 seconds to print all the numbers. That is 10e956 billion years."
Anyway, if you wish wait:
BigInteger n = BigInteger.ONE;
BigInteger last = BigInteger.TEN.pow(1000);
while(n.compareTo(last) < 0) {
System.out.println(n);
n = n.add(BigInteger.ONE);
}
Assuming only System.out.print is able to use (String is a library, see [3]), a possible solution without copy over and over again strings, and with the expected output could be:
static void printDigits(int n) {
ds(0, n, new byte[n]);
}
static void ds(int p, int k, byte[] d) {
if (p < d.length) { // if more digits to print
for (byte i = 0; i < 10; i++) { // from digit 0 to 9
d[p] = i; // set at this position
ds(p + 1, i == 0 ? k : (p < k ? p : k), d); // populate next storing first non-zero
}
} else {
if(k < d.length) { // if is not zero
if(k < d.length - 1 || d[d.length - 1] != 1) // if is not one
System.out.print(", "); // print separator
for(int i = k; i < d.length; i++) // for each digit
System.out.print((char)('0' + d[i])); // print
}
}
}
then, for printDigits(5) the output is
1, 2, 3, 4, ..., 99999
[1] https://epsnews.com/2020/09/14/total-microprocessor-sales-to-edge-slightly-higher-in-2020/
[2] https://en.wikipedia.org/wiki/Clock_rate
[3] https://docs.oracle.com/javase/7/docs/api/java/lang/String.html
Using recursion (if only to print):
void digits(int count) {
if (count < 0) throw new IllegalArgumentException("invalid count: " + count);
digits(count, "");
}
void digits(int count, String text) {
if (count == 0) {
System.out.println(text);
} else {
for (var i = 0; i < 10; i++) {
if (i == 0 && text.isEmpty()) {
digits(count-1, text);
} else {
digits(count-1, text+i);
}
}
}
}
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;
}
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