I have on the first problem of Google Foobar Level 2. The problem is:
Being a henchman isn't all drudgery. Occasionally, when feeling generous, Commander Lambda hand out Lucky LAMBs (Lambda's All-purpose Money Bucks). Henchmen can use Lucky LAMBs to buy things like a second pair of socks, a pillow for their bunks, or even a third daily meal!
However, actually passing out LAMBs isn't easy. Each henchman squad has a strict seniority ranking which must be respected -- or else the henchmen will revolt and you'll all get demoted back to minions again!
There are 4 key rules which you must follow in order to avoid a revolt:
1. The most junior henchman (with the least seniority) gets exactly 1 LAMB. (There will always be at least 1 henchman on a team.)
2. A henchman will revolt if the person who ranks immediately above them gets more than double the number of LAMBs they do.
3. A henchman will revolt if the amount of LAMBs given to their next two subordinates combined is more than the number of LAMBs they get. (Note that the two most junior henchmen won't have two subordinates, so this rule doesn't apply to them. The 2nd most junior henchman would require at least as many LAMBs as the most junior henchman.)
4. You can always find more henchmen to pay - the Commander has plenty of employees. If there are enough LAMBs left over such that another henchman could be added as the most senior while obeying the other rules, you must always add and pay that henchman.
Note that you may not be able to hand out all the LAMBs. A single LAMB cannot be subdivided. That is, all henchmen must get a positive integer number of LAMBs.
Write a function called solution(total_lambs), where total_lambs is the integer number of LAMBs in the handout you are trying to divide. It should return an integer which represents the difference between the minimum and maximum number of henchmen who can share the LAMBs (that is, being as generous as possible to those you pay and as stingy as possible, respectively) while still obeying all of the above rules to avoid a revolt. For instance, if you had 10 LAMBs and were as generous as possible, you could only pay 3 henchmen (1, 2, and 4 LAMBs, in order of ascending seniority), whereas if you were as stingy as possible, you could pay 4 henchmen (1, 1, 2, and 3 LAMBs). Therefore, solution(10) should return 4-3 = 1.
To keep things interesting, Commander Lambda varies the sizes of the Lucky LAMB payouts. You can expect total_lambs to always be a positive integer less than 1 billion (10 ^ 9).
My code:
public class Solution {
public static int solution(int total_lambs) {
// person 1 gets 1 lamb
// person 2 gets more than 1 lamb
// person 3 gets more than or = person 1 + person 2 but less or = than double person 2
// person 4 gets more than person 3 + person 2 but less than or = double person 3
return (solution_conservative(total_lambs) - solution_generous(total_lambs));
}
public static int solution_generous(int total_lambs) {
int lamb_pay_current = 0;
int person_before = 0;
//int person_before_before = 0;
int person_counter = 0;
for (int lamb_pay_cumm = 0; lamb_pay_cumm < total_lambs; lamb_pay_cumm += lamb_pay_current) {
if (!(total_lambs > 0)) {break;}
if ((total_lambs == 1)) {break;}
if ((lamb_pay_cumm == 0) && (total_lambs > 0)) {
lamb_pay_current = 1;
person_counter++;
continue;
}
if ((lamb_pay_cumm) == 1 && (total_lambs > 1)) {
lamb_pay_current = 2;
person_before = 1;
person_counter++;
continue;
}
if (person_before == 1) {
person_before = 2;
}
if (person_before * 2 + lamb_pay_cumm > total_lambs) {continue;}
lamb_pay_current = person_before * 2;
person_counter++;
// person_before_before = person_before;
person_before = lamb_pay_current;
}
if (total_lambs == 1) {return 1;}
if (!(total_lambs > 0)) {return 0;}
return person_counter;
}
public static int solution_conservative(int total_lambs) {
int lamb_pay_current = 0;
int person_before = 0;
int person_before_before = 0;
int person_counter = 0;
for (int lamb_pay_cumm = 0; lamb_pay_cumm < total_lambs; lamb_pay_cumm += lamb_pay_current) {
if (!(total_lambs > 0)) {break;}
if ((total_lambs == 1)) {break;}
if ((lamb_pay_cumm == 0) && (total_lambs > 0)) {
lamb_pay_current = 1;
person_counter++;
continue;
}
if ((lamb_pay_cumm) == 1 && (total_lambs > 1)) {
lamb_pay_current = 1;
person_before = 1;
person_counter++;
continue;
}
if (person_before == 1) {
person_before_before = 1;
}
if (person_before + person_before_before + lamb_pay_cumm > total_lambs) {continue;}
lamb_pay_current = person_before + person_before_before;
person_counter++;
person_before_before = person_before;
person_before = lamb_pay_current;
}
if (total_lambs == 1) {return 1;}
if (!(total_lambs > 0)) {return 0;}
return person_counter;
}
}
What I am trying to get done is that I have 2 functions. One is to find the most "generous" possible way to give everyone the most amount of LAMBS possible before someone revolts. This pattern appears to be like this: 1, 2, 4, 8, 16 etc. I may be wrong. The other function is to find the most "conservative" possible way to give everyone the least amount of LAMBS possible before someone revolts. This pattern appears to be like this: 1, 1, 2, 3, 5, 8, 13, etc. I may also be wrong.
Whenever I do
"verify Solutions.java", it always fails Test #7. All other tests succeed, just this one fails. And I don't know what Test #7 is.
i have also tried most of the tests i knew of on Intellij Idea but all of them looked correct to me...
You are right about the patterns of generous and stingy. Generous path follows powers of two and the stingy follows pattern of fibonacci.
It is hard to figure out what is wrong with your code. But I think most probably your code doesn't calculate the number of henchmen correctly especially when there are remaining lambs that can be handed out without violating the restrictions.
Generous:
Start with the power of two = 1 and keep taking powers of two and adding to lambs to be paid, until you exceed the total_lambs. When you exceed make sure that you subtract the excess from the paid out lambs, so you get the original lambs paid. Also get the last two paid lambs which can be easily obtained by:
current_power_of_two/2 + current_power_of_two/4
See if it is less than or equal to remaining lambs = total_lambs - lambs_paid, then increment the henchmen by 1.
Stingy: Its the same approach except here you keep track of the last two paid lambs in the fibonacci series.
Here is one straightforward implementation for both generous and stingy handouts:
public static int solution_generous(int total_lambs) {
// Apply power of two
int power_of_two = 1;
int henchmen = 1;
int lambs_paid = 1;
while ( lambs_paid <= total_lambs ) {
power_of_two = 2*power_of_two;
lambs_paid += power_of_two;
if ( lambs_paid > total_lambs ) {
lambs_paid -= power_of_two;
power_of_two = power_of_two/2;
break;
}
henchmen++;
}
int last_one = power_of_two;
int last_before_one = power_of_two/2;
if ( last_one + last_before_one <= total_lambs - lambs_paid ) {
henchmen++;
}
return henchmen;
}
public static int solution_conservative(int total_lambs) {
//Fibonacci
int f1 = 1;
int f2 = 1;
int f12 = f1 + f2;
int henchmen = 1;
int lambs_paid = f1;
int last_two_paid = f2;
while ( lambs_paid <= total_lambs ) {
last_two_paid = f2;
f1 = f2;
f2 = f12;
f12 = f1 + f2;
lambs_paid += f1;
if ( lambs_paid > total_lambs ) {
break;
}
henchmen++;
}
if ( last_two_paid <= total_lambs - lambs_paid ) {
henchmen++;
}
return henchmen;
}
Related
I recently came across an interview question which although had an immediately obvious solution, I struggled to find a more efficient one.
The actual question involved counting numbers from a to b (up to 2^64) which satisfied having either the digit 6 or 8, but not both. They called it a 'lucky number'. So for example:
126 - lucky
88 - lucky
856 - not lucky
The obvious thought was to brute force it by testing each number between a and b as a string, to check for the relevant characters. However, this was prohibitively slow as expected.
A much better solution that I tried, involved first computing all the 'lucky numbers' which had the number of digits between the number of digits that a and b have (by counting possible combinations):
long n = 0;
for (int occurrences = 1; occurrences <= maxDigits; occurrences++) {
n += (long) Math.pow(8, digits - occurrences) * choose(digits, occurrences);
}
return 2 * n;
and then using the brute force method to compute the number of extra lucky numbers that I had counted. So for example, if a = 3 and b = 21, I could count the number of 1 and 2 digit lucky numbers, then subtract the count of those in [1, 3) and (21, 99].
However, although this was a massive improvement, the brute force element still slowed it down way too much for most cases.
I feel like there must be something I am missing, as the rest of the interview questions were relatively simple. Does anyone have any idea of a better solution?
Although I have tagged this question in Java, help in any other languages or pseudocode would be equally appreciated.
I would say you are at the right track. The gut feeling is that dealing with the a and b separately is easier. Making a function count_lucky_numbers_below(n) allows
return count_lucky_numbers_below(b) - count_lucky_numbers_below(a);
The combinatorial approach is definitely a way to go (just keep in mind that the sum is actually equal to 9**n - 8**n, and there is no need to compute the binomial coefficients).
The final trick is to recurse down by a numbeer of digits.
Lets say n is an N-digit number, and the most significant digit is 5. Each set of N-digit numbers starting with a smaller digit contributes S = 9**(N-1) - 8**(N-1) to the total; you immediately have 5*S of lucky numbers. To deal with the remainder, you need to compute the lucky numbers for the N-1-digit tail.
Of course, care must be taken if the most significant digit is above 5. You need to special case it being 6 or 8, but it doesn't seem to be too complicated.
In the end the answer from #user58697 pushed me in the right direction towards finding a solution. With my (albeit extremely primitive) benchmark, it handles 1 to 2^63 - 1 in less than 2 nanoseconds, so it is definitely fast enough. However it is still more verbose than I would have liked, especially given that I was originally expected to write it in half an hour, so I feel like there is still an easier solution that gives comparable performance.
long countLuckyNumbersBetween(long a, long b) {
return countLuckyNumbersBelow(b) - countLuckyNumbersBelow(a - 1);
}
long countLuckyNumbersBelow(long n) {
return countNumbers(n, 6, 8) + countNumbers(n, 8, 6);
}
/**
* Counts the natural numbers in [0, {to}] that have {including} as a digit, but not {excluding}.
* {excluding} should be in (0, 9] or -1 to exclude no digit.
*/
long countNumbers(long to, int including, int excluding) {
if (including == -1) return 0;
if (to < 10) {
if (to >= including) {
return 1;
} else {
return 0;
}
}
int nSignificand = significand(to);
int nDigits = countDigits(to);
long nTail = to % (long) Math.pow(10, nDigits - 1);
// The count of numbers in [0, 10^(nDigits-1)) that include and exclude the relevant digits
long bodyCount;
if (excluding == -1) {
bodyCount = (long) (Math.pow(10, nDigits - 1) - Math.pow(9, nDigits - 1));
} else {
bodyCount = (long) (Math.pow(9, nDigits - 1) - Math.pow(8, nDigits - 1));
}
long count = 0;
for (int i = 0; i < nSignificand; i++) {
if (i == including) {
if (excluding == -1) {
count += Math.pow(10, nDigits - 1);
} else {
count += Math.pow(9, nDigits - 1);
}
} else if (i != excluding) {
count += bodyCount;
}
}
if (nSignificand == including) {
count += 1 + nTail - countNumbers(nTail, excluding, -1);
} else if (nSignificand != excluding) {
count += countNumbers(nTail, including, excluding);
}
return count;
}
int significand(long n) {
while (n > 9) n /= 10;
return (int) n;
}
int countDigits(long n) {
if (n <= 1) {
return 1;
} else {
return (int) (Math.log10(n) + 1);
}
}
Here is another approach:
264 = 18446744073709551616
We can represent the number as a sum of components (one component per every digit position):
18446744073709551616 associated range of numbers
———————————————————— ———————————————————————————————————————————
0xxxxxxxxxxxxxxxxxxx => [00000000000000000000;09999999999999999999]
17xxxxxxxxxxxxxxxxxx => [10000000000000000000;17999999999999999999]
183xxxxxxxxxxxxxxxxx => [18000000000000000000;18399999999999999999]
1843xxxxxxxxxxxxxxxx => [18400000000000000000;18439999999999999999]
18445xxxxxxxxxxxxxxx => [18440000000000000000;18445999999999999999]
...
1844674407370955160x => [18446744073709551600;18446744073709551609]
18446744073709551616 => [18446744073709551610;18446744073709551616]
If we could compute the amount of lucky numbers for every component, then the sum of the amounts for every component will be the total amount for 264.
Note that every component consists of a prefix followed by xs.
Imagine that we know how many lucky numbers there are in an n-digit xx..x (i.e. numbers [0..0 - 9..9]), let's call it N(n).
Now let's look at a component 18445x..x. where 18445 is a prefix and an n-digit xx..x.
In this component we look at all numbers from 18440xx..x to 18445xx..x.
For every item 1844dxx..x we look at the prefix 1844d:
if prefix contains no 6 or 8, then it's the same as x..x without prefix => N(n) special numbers
if prefix contains 6 and no 8, then x..x cannot contain 8 => 9ⁿ special numbers
if prefix contains 8 and no 6, then x..x cannot contain 6 => 9ⁿ special numbers
if prefix contains 6 and 8 => 0 special numbers
Now let's compute N(n) — the amount of lucky numbers in an n-digit xx..x (i.e. in [0..0 - 9..9]).
We can do it iteratively:
n=1: there are only 2 possible numbers: 8 and 6 => N(1)=2.
n=2: there are 2 groups:
8 present: 8x and x8 where x is any digit except 6
6 present: 6x and x6 where x is any digit except 8
=> N(2)=4*9=34.
n=3: let's fix the 1st digit:
0xx — 5xx, 7xx, 9xx => 8 * N(2)
6xx: xx are any 2 digits except 8 => 9²
8xx: xx are any 2 digits except 6 => 9²
=> N(3) = 8*N(2) + 2*9².
n=k+1 => N(k+1) = 7*N(k) + 2*9ᵏ
Here is an implementation (not 100% tested):
public final class Numbers {
public long countLuckyNumbersBelow(BigInteger num) {
if (num.compareTo(BigInteger.ZERO) < 0) {
throw new IllegalArgumentException("num < 0: " + num);
}
var numberText = num.toString();
var result = 0L;
for (var digitPosition = 0; digitPosition < numberText.length(); digitPosition++) {
result += countLuckyNumbersForComponent(numberText, digitPosition);
}
return result;
}
private long countLuckyNumbersForComponent(String numberText, int digitPosition) {
var prefixEndIdx = numberText.length() - 1 - digitPosition;
var prefixHas6s = containsChar(numberText, '6', prefixEndIdx);
var prefixHas8s = containsChar(numberText, '8', prefixEndIdx);
if (prefixHas6s && prefixHas8s) {
return 0;
}
var result = 0L;
for (var c = numberText.charAt(prefixEndIdx) - 1; c >= '0'; c--) {
var compNo6s = (!prefixHas6s) && (c != '6');
var compNo8s = (!prefixHas8s) && (c != '8');
if (compNo6s && compNo8s) {
result += countLuckyNumbers(digitPosition);
} else if (compNo6s || compNo8s) {
result += power9(digitPosition);
}
}
return result;
}
private static boolean containsChar(String text, char c, int endIdx) {
var idx = text.indexOf(c);
return (idx > 0) && (idx < endIdx);
}
private long[] countLuckyNumbersCache = {0L, 0L};
/**
* Computes how many lucky numbers are in an n-digit `xx..x`
*/
private long countLuckyNumbers(int numDigits) {
if (countLuckyNumbersCache[0] == numDigits) {
return countLuckyNumbersCache[1];
}
long N;
if (numDigits <= 1) {
N = (numDigits == 1) ? 2 : 0;
} else {
var prevN = countLuckyNumbers(numDigits - 1);
N = (8 * prevN) + (2 * power9(numDigits-1));
}
countLuckyNumbersCache[0] = numDigits;
countLuckyNumbersCache[1] = N;
return N;
}
private long[] power9Cache = {0L, 1L};
/**
* Computes 9<sup>power</sup>
*/
private long power9(int power) {
if (power9Cache[0] == power) {
return power9Cache[1];
}
long res = 1;
var p = power;
if (power > power9Cache[0]) {
p -= power9Cache[0];
res = power9Cache[1];
}
for (; p > 0; p--) {
res *= 9;
}
power9Cache[0] = power;
power9Cache[1] = res;
return res;
}
}
BTW it took me half a day, and I have no idea how is that possible to complete it in 30 minutes.
I guess your interviewers expected from you to demonstrate them your thought process.
Here is the result of my attempt.
First, let me explain a little bit what logic I used.
I used formula S = 9N — 8N (mentioned in the user58697's answer) to compute how many of N-digit numbers are lucky.
How to get this formula:
for N-digit numbers there are 10N numbers in total: N digits, each can take one of 10 values: [0-9].
if we only count numbers without 6, then each digit can only take one of 9 values [0-5,7-9] — it's 9N numbers in total
now we also want only numbers with 8.
We can easily compute how many numbers don't have both 6 and 8: digits in these numbers can only take one of 8 values [0-5,7,9] — it's 8N numbers in total.
As a result, there are S = 9N — 8N numbers which have 8 and no 6.
For numbers with 6 and without 8 the formula is the same.
Also numbers without 6 do not intersect with numbers without 8 — so we can just sum them.
And finally, since we know how to count lucky numbers for intervals [0;10N], we need to split the interval [0; our arbitrary number] into suitable sub-intervals.
For instance, we can split number 9845637 this way:
Sub-interval
Prefix
Digit
N-digit interval
0000000 - 8999999
0 - 8
000000 - 999999
9000000 - 9799999
9
0 - 7
00000 - 99999
9800000 - 9839999
98
0 - 3
0000 - 9999
9840000 - 9844999
984
0 - 4
000 - 999
9845000 - 9845599
9845
0 - 5
00 - 99
9845600 - 9845629
98456
0 - 2
0 - 9
9845630 - 9845637
Now we can compute the number for every sub-interval (just keep attention to digits in prefix — they might contains 8 or 6) and then just sum those numbers to get the final result.
Here is the code:
// Special value for 'requiredDigit': no required digit
private static char NIL = Character.MAX_VALUE;
public static long countLuckyNumbersUpTo(BigInteger number) {
if (number.compareTo(BigInteger.ZERO) < 0) {
throw new IllegalArgumentException("number < 0: " + number);
}
var numberAsDigits = number.toString();
return countNumbersUpTo(numberAsDigits, '6', '8') + countNumbersUpTo(numberAsDigits, '8', '6');
}
// count all numbers in [0;'numberAsDigits'] which have 'requiredDigit' and no 'excludeDigit'
private static long countNumbersUpTo(String numberAsDigits, char requiredDigit, char excludeDigit) {
var highDigit = numberAsDigits.charAt(0);
if (numberAsDigits.length() == 1) {
return (requiredDigit != NIL)
? ((highDigit >= requiredDigit) ? 1 : 0)
: numDigitsInInterval('0', highDigit, excludeDigit);
}
var tailDigits = numberAsDigits.substring(1);
var result = 0L;
// numbers where the highest digit is in [0;`highDigit`)
var numGoodDigits = numDigitsInInterval('0', (char) (highDigit - 1), excludeDigit);
var containsRequiredDigit = (requiredDigit != NIL) && (highDigit > requiredDigit);
if (containsRequiredDigit) {
result += totalNumbers(tailDigits.length(), NIL);
numGoodDigits--;
}
if (numGoodDigits > 0) {
result += numGoodDigits * totalNumbers(tailDigits.length(), requiredDigit);
}
// remaining numbers where the highest digit is `highDigit`
if (highDigit != excludeDigit) {
var newRequiredDigit = (highDigit == requiredDigit) ? NIL : requiredDigit;
result += countNumbersUpTo(tailDigits, newRequiredDigit, excludeDigit);
}
return result;
}
private static int numDigitsInInterval(char firstDigit, char lastDigit, char excludeDigit) {
var totalDigits = lastDigit - firstDigit + 1;
return (excludeDigit <= lastDigit) ? (totalDigits - 1) : totalDigits;
}
// total numbers with given requiredDigit in [0;10^numDigits)
private static long totalNumbers(int numDigits, char requiredDigit) {
return (requiredDigit == NIL) ? pow(9, numDigits) : (pow(9, numDigits) - pow(8, numDigits));
}
private static long pow(int base, int exponent) {
return BigInteger.valueOf(base).pow(exponent).longValueExact();
}
This is the question:
You are given Q queries. Each query consists of a single number N . You can perform any of the operations on in each move:
If we take 2 integers a and b where N=a*b (a ,b cannot be equal to 1), then we can change N=max(a,b)
Decrease the value of N by 1 .
Determine the minimum number of moves required to reduce the value of to .
Input Format
The first line contains the integer Q.
The next Q lines each contain an integer,N .
Output Format
Output Q lines. Each line containing the minimum number of moves required > to reduce the value of N to 0.
I have written the following code. This code is giving some wrong answers and also giving time limit exceed error . Can you tell what are the the mistakes present in my code ? where or what I am doing wrong here?
My code:
public static int downToZero(int n) {
// Write your code here
int count1=0;
int prev_i=0;
int prev_j=0;
int next1=0;
int next2=Integer.MAX_VALUE;
if (n==0){
return 0;
}
while(n!=0){
if(n==1){
count1++;
break;
}
next1=n-1;
outerloop:
for (int i=1;i<=n;i++){
for (int j=1;j<=n;j++){
if (i*j==n){
if (prev_i ==j && prev_j==i){
break outerloop;
}
if (i !=j){
prev_i=i;
prev_j=j;
}
int max=Math.max(i,j);
if (max<next2){
next2=max;
}
}
}
}
n=Math.min(next1,next2);
count1++;
}
return count1;
}
This is part is coded for us:
public class Solution {
public static void main(String[] args) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(System.getenv("OUTPUT_PATH")));
int q = Integer.parseInt(bufferedReader.readLine().trim());
for (int qItr = 0; qItr < q; qItr++) {
int n = Integer.parseInt(bufferedReader.readLine().trim());
int result = Result.downToZero(n);
bufferedWriter.write(String.valueOf(result));
bufferedWriter.newLine();
}
bufferedReader.close();
bufferedWriter.close();
}
}
Ex: it is not working for number 7176 ....
To explore all solution tree and find globally optimal solution, we must choose the best result both from all possible divisor pairs and from solution(n-1)
My weird translation to Java (ideone) uses bottom-up dynamic programming to make execution faster.
We calculate solutions for values i from 1 to n, they are written into table[i].
At first we set result into 1 + best result for previous value (table[i-1]).
Then we factor N into all pairs of divisors and check whether using already calculated result for larger divisor table[d] gives better result.
Finally we write result into the table.
Note that we can calculate table once and use it for all Q queries.
class Ideone
{
public static int makezeroDP(int n){
int[] table = new int[n+1];
table[1] = 1; table[2] = 2; table[3] = 3;
int res;
for (int i = 4; i <= n; i++) {
res = 1 + table[i-1];
int a = 2;
while (a * a <= i) {
if (i % a == 0)
res = Math.min(res, 1 + table[i / a]);
a += 1;
}
table[i] = res;
}
return table[n];
}
public static void main (String[] args) throws java.lang.Exception
{
int n = 145;//999999;
System.out.println(makezeroDP(n));
}
}
Old part
Simple implementation (sorry, in Python) gives answer 7 for 7176
def makezero(n):
if n <= 3:
return n
result = 1 + makezero(n - 1)
t = 2
while t * t <= n:
if n % t == 0:
result = min(result, 1 + makezero(n // t))
t += 1
return result
In Python it's needed to set recursion limit or change algorithm. Now use memoization, as I wrote in comments).
t = [-i for i in range(1000001)]
def makezeroMemo(n):
if t[n] > 0:
return t[n]
if t[n-1] < 0:
res = 1 + makezeroMemo(n-1)
else:
res = 1 + t[n-1]
a = 2
while a * a <= n:
if n % a == 0:
res = min(res, 1 + makezeroMemo(n // a))
a += 1
t[n] = res
return res
Bottom-up table dynamic programming. No recursion.
def makezeroDP(n):
table = [0,1,2,3] + [0]*(n-3)
for i in range(4, n+1):
res = 1 + table[i-1]
a = 2
while a * a <= i:
if i % a == 0:
res = min(res, 1 + table[i // a])
a += 1
table[i] = res
return table[n]
We can construct the directed acyclic graph quickly with a sieve and
then compute shortest paths. No trial division needed.
Time and space usage is Θ(N log N).
n_max = 1000000
successors = [[n - 1] for n in range(n_max + 1)]
for a in range(2, n_max + 1):
for b in range(a, n_max // a + 1):
successors[a * b].append(b)
table = [0]
for n in range(1, n_max + 1):
table.append(min(table[s] for s in successors[n]) + 1)
print(table[7176])
Results:
7
EDIT:
The algorithm uses Greedy approach and doesn't return optimal results, it just simplifies OP's approach. For 7176 given as example, below algorithm returns 10, I can see a shorter chain of 7176 -> 104 -> 52 -> 13 -> 12 -> 4 -> 2 -> 1 -> 0 with 8 steps, and expected answer is 7.
Let's review your problem in simple terms.
If we take 2 integers a and b where N=a*b (a ,b cannot be equal to 1), then we can change N=max(a,b)
and
Determine the minimum number of moves required to reduce the value of to .
You're looking for 2 factors of N, a and b and, if you want the minimum number of moves, this means that your maximum at each step should be minimum. We know for a fact that this minimum is reached when factors are closest to N. Let me give you an example:
36 = 1 * 36 = 2 * 18 = 3 * 12 = 4 * 9 = 6 * 6
We know that sqrt(36) = 6 and you can see that the minimum of 2 factors you can get at this step is max(6, 6) = 6. Sure, 36 is 6 squared, let me take a number without special properties, 96, with its square root rounded down to nearest integer 9.
96 = 2 * 48 = 3 * 32 = 4 * 24 = 6 * 16 = 8 * 12
You can see that your minimum value for max(a, b) is max(8, 12) = 12, which is, again, attained when factors are closest to square root.
Now let's look at the code:
for (int i=1;i<=n;i++){
for (int j=1;j<=n;j++){
if (i*j==n){
You can do this in one loop, knowing that n / i returns an integer, therefore you need to check if i * (n / i) == n. With the previous observation, we need to start at the square root, and go down, until we get to 1. If we got i and n / i as factors, we know that this pair is also the minimum you can get at this step. If no factors are found and you reach 1, which obviously is a factor of n, you have a prime number and you need to use the second instruction:
Decrease the value of N by 1 .
Note that if you go from sqrt(n) down to 1, looking for factors, if you find one, max(i, n / i) will be n / i.
Additionally, if n = 1, you take 1 step. If n = 2, you take 2 steps (2 -> 1). If n = 3, you take 3 steps (3 -> 2 -> 1). Therefore if n is 1, 2 or 3, you take n steps to go to 0. OK, less talking, more coding:
static int downToZero(int n) {
if (n == 1 || n == 2 || n == 3) return n;
int sqrt = (int) Math.sqrt(n);
for (int i = sqrt; i > 1; i--) {
if (n / i * i == n) {
return 1 + downToZero(n / i);
}
}
return 1 + downToZero(n - 1);
}
Notice that I'm stopping when i equals 2, I know that if I reach 1, it's a prime number and I need to go a step forward and look at n - 1.
However, I have tried to see the steps your algorithm and mine takes, so I've added a print statement each time n changes, and we both have the same succession: 7176, 92, 23, 22, 11, 10, 5, 4, 2, 1, which returns 10. Isn't that correct?
So, I found a solution which is working for all the test cases -
static final int LIMIT = 1_000_000;
static int[] solutions = buildSolutions();
public static int downToZero(int n) {
// Write your code here
return solutions[n];
}
static int[] buildSolutions() {
int[] solutions = new int[LIMIT + 1];
for (int i = 1; i < solutions.length; i++) {
solutions[i] = solutions[i - 1] + 1;
for (int j = 2; j * j <= i; j++) {
if (i % j == 0) {
solutions[i] = Math.min(solutions[i], solutions[i / j] + 1);
}
}
}
return solutions;
}
}
I am trying to solve this question as the preparation for a programming interview:
A frog only moves forward, but it can move in steps 1 inch long or in jumps 2 inches long. A frog can cover the same distance using different combinations of steps and jumps.
Write a function that calculates the number of different combinations a frog can use to cover a given distance.
For example, a distance of 3 inches can be covered in three ways: step-step-step, step-jump, and jump-step.
I think there is a quite simple solution to this, but I just can't seem to find it. I would like to use recursion, but I can't see how. Here is what I have so far:
public class Frog {
static int combinations = 0;
static int step = 1;
static int jump = 2;
static int[] arr = {step, jump};
public static int numberOfWays(int n) {
for (int i = 0; i < arr.length; i++) {
int sum = 0;
sum += arr[i];
System.out.println("SUM outer loop: " + sum + " : " + arr[i]);
while (sum != 3) {
for (int j = 0; j < arr.length; j++) {
if (sum + arr[j] <= 3) {
sum += arr[j];
System.out.println("SUM inner loop: " + sum + " : " + arr[j]);
if (sum == 3) {
combinations++;
System.out.println("Combinations " + combinations);
}
}
}
}
}
return combinations;
}
public static void main(String[] args) {
System.out.println(numberOfWays(3));
}
}
It doesn't find all combinations, and I think the code is quite bad. Anyone have a good solution to this question?
Think you have an oracle that knows how to solve the problem for "smaller problems", you just need to feed it with smaller problems. This is the recursive method.
In your case, you solve foo(n), by splitting the possible moves the frog can do in the last step, and summing them):
foo(n) = foo(n-1) + foo(n-2)
^ ^
1 step 2 steps
In addition, you need a stop clause of foo(0) = 1, foo(1)=1 (one way to move 0 or 1 inches).
Is this recursive formula looks familiar? Can you solve it better than the naive recursive solution?
Spoiler:
Fibonacci Sequence
Here's a simple pseudo-code implementation that should work:
var results = []
function plan(previous, n){
if (n==0) {
results.push(previous)
} else if (n > 0){
plan(previous + ' step', n-1)
plan(previous + ' hop', n-2)
}
}
plan('', 5)
If you want to improve the efficiency of an algorithm like this you could look into using memoization
Here's a combinatoric way: think of n as 1 + 1 + 1 ... = n. Now bunch the 1's in pairs, gradually increasing the number of bunched 1's, summing the possibilities to arrange them.
For example, consider 5 as 1 1 1 1 1:
one bunch => (1) (1) (1) (11) => 4 choose 1 possibilities to arrange one 2 with three 1's
two bunches => (1) (11) (11) => 3 choose 2 possibilities to arrange two 2's with one 1
etc.
This seems directly related to Wikipedia's description of Fibonacci numbers' "Use in Mathematics," for example, in counting "the number of compositions of 1s and 2s that sum to a given total n" (http://en.wikipedia.org/wiki/Fibonacci_number).
This logic is working fine. (Recursion)
public static int numberOfWays(int n) {
if (n== 1) {
return 1; // step
} else if (n== 2) {
return 2; // (step + step) or jump
} else {
return numberOfWays(n- 1)
+ numberOfWays(n- 2);
}
}
The accepted answer fails performance test for larger sets. Here is a version with for loop that satisfies performance tests at testdome.
using System;
public class Frog
{
public static int NumberOfWays (int n)
{
int first = 0, second = 1;
for ( int i = 0; i<n; i++ )
{
int at = first;
first = second;
second = at + second;
}
return second;
}
public static void Main (String[] args)
{
Console.WriteLine (NumberOfWays (3));
}
}
C++ code works fine.
static int numberOfWays(int n)
{
if (n == 1) return 1;
else if (n == 2) return 2;
else
{
static std::unordered_map<int,int> m;
auto i = m.find(n);
if (i != m.end())
return i->second;
int x = numberOfWays(n - 1) + numberOfWays(n - 2);
m[n] = x;
return x;
}
}
I am stuck on the coin denomination problem.
I am trying to find the lowest number of coins used to make up $5.70 (or 570 cents). For example, if the coin array is {100,5,2,5,1} (100 x 10c coins, 5 x 20c, 2 x 50c, 5 x $1, and 1 x $2 coin), then the result should be {0,1,1,3,1}
At the moment the coin array will consist of the same denominations ( $2, $1, 50c, 20c, 10c)
public static int[] makeChange(int change, int[] coins) {
// while you have coins of that denomination left and the total
// remaining amount exceeds that denomination, take a coin of that
// denomination (i.e add it to your result array, subtract it from the
// number of available coins, and update the total remainder). –
for(int i= 0; i< coins.length; i++){
while (coins[i] > 0) {
if (coins[i] > 0 & change - 200 >= 0) {
coins[4] = coins[4]--;
change = change - 200;
} else
if (coins[i] > 0 & change - 100 >= 0) {
coins[3] = coins[3]--;
change = change - 100;
} else
if (coins[i] > 0 & change - 50 >= 0) {
coins[2] = coins[2]--;
change = change - 50;
} else
if (coins[i] > 0 & change - 20 >= 0) {
coins[1] = coins[1]--;
change = change - 20;
} else
if (coins[i] > 0 & change - 10 >= 0) {
coins[0] = coins[0]--;
change = change - 10;
}
}
}
return coins;
}
I am stuck on how to deduct the values from coins array and return it.
EDIT: New code
The brute force solution is to try up to the available number of coins of the highest denomination (stopping when you run out or the amount would become negative) and for each of these recurse on solving the remaining amount with a shorter list that excludes that denomination, and pick the minimum of these. If the base case is 1c the problem can always be solved, and the base case is return n otherwise it is n/d0 (d0 representing the lowest denomination), but care must be taken to return a large value when not evenly divisible so the optimization can pick a different branch. Memoization is possible, and parameterized by the remaining amount and the next denomination to try. So the memo table size would be is O(n*d), where n is the starting amount and d is the number of denominations.
So the problem can be solved in pseudo-polynomial time.
The wikipedia link is sparse on details on how to decide if a greedy algorithm such as yours will work. A better reference is linked in this CS StackExchange question. Essentially, if the coin system is canonical, a greedy algorithm will provide an optimal solution. So, is [1, 2, 5, 10, 20] canonical? (using 10s of cents for units, so that the sequence starts in 1)
According to this article, a 5-coin system is non-canonical if and only if it satisfies exactly one of the following conditions:
[1, c2, c3] is non-canonical (false for [1, 2, 5])
it cannot be written as [1, 2, c3, c3+1, 2*c3] (true for [1, 2, 5, 10, 20])
the greedyAnswerSize((k+1) * c4) > k+1 with k*c4 < c5 < (k+1) * c4; in this case, this would require a k*10 < 20 < (k+1)*10; there is no integer k in that range, so this is false for [1, 2, 5, 10, 20].
Therefore, since the greedy algorithm will not provide optimal answers (and even if it did, I doubt that it would work with limited coins), you should try dynamic programming or some enlightened backtracking:
import java.util.HashSet;
import java.util.PriorityQueue;
public class Main {
public static class Answer implements Comparable<Answer> {
public static final int coins[] = {1, 2, 5, 10, 20};
private int availableCoins[] = new int[coins.length];
private int totalAvailable;
private int totalRemaining;
private int coinsUsed;
public Answer(int availableCoins[], int totalRemaining) {
for (int i=0; i<coins.length; i++) {
this.availableCoins[i] = availableCoins[i];
totalAvailable += coins[i] * availableCoins[i];
}
this.totalRemaining = totalRemaining;
}
public boolean hasCoin(int coinIndex) {
return availableCoins[coinIndex] > 0;
}
public boolean isPossibleBest(Answer oldBest) {
boolean r = totalRemaining >= 0
&& totalAvailable >= totalRemaining
&& (oldBest == null || oldBest.coinsUsed > coinsUsed);
return r;
}
public boolean isAnswer() {
return totalRemaining == 0;
}
public Answer useCoin(int coinIndex) {
Answer a = new Answer(availableCoins, totalRemaining - coins[coinIndex]);
a.availableCoins[coinIndex]--;
a.totalAvailable = totalAvailable - coins[coinIndex];
a.coinsUsed = coinsUsed+1;
return a;
}
public int getCoinsUsed() {
return coinsUsed;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder("{");
for (int c : availableCoins) sb.append(c + ",");
sb.setCharAt(sb.length()-1, '}');
return sb.toString();
}
// try to be greedy first
#Override
public int compareTo(Answer a) {
int r = totalRemaining - a.totalRemaining;
return (r==0) ? coinsUsed - a.coinsUsed : r;
}
}
// returns an minimal set of coins to solve
public static int makeChange(int change, int[] availableCoins) {
PriorityQueue<Answer> queue = new PriorityQueue<Answer>();
queue.add(new Answer(availableCoins, change));
HashSet<String> known = new HashSet<String>();
Answer best = null;
int expansions = 0;
while ( ! queue.isEmpty()) {
Answer current = queue.remove();
expansions ++;
String s = current.toString();
if (current.isPossibleBest(best) && ! known.contains(s)) {
known.add(s);
if (current.isAnswer()) {
best = current;
} else {
for (int i=0; i<Answer.coins.length; i++) {
if (current.hasCoin(i)) {
queue.add(current.useCoin(i));
}
}
}
}
}
// debug
System.out.println("After " + expansions + " expansions");
return (best != null) ? best.getCoinsUsed() : -1;
}
public static void main(String[] args) {
for (int i=0; i<100; i++) {
System.out.println("Solving for " + i + ":"
+ makeChange(i, new int[]{100,5,2,5,1}));
}
}
}
You are in wrong direction. This program will not give you an optimal solution. To get optimal solution go with dynamic algorithms implemented and discussed here. Please visit these few links:
link 1
link 2
link 3
So I wrote a recursive algorithm for the problem of figuring out the least number of 'coins' of a particular set of denominations possible to arrive at a given sum. The algorithm seems to work, but because it's recursive, and calculates every possible option before choosing one or the other, I'm having a difficult time coming up with a way to print out the denominations used as well. So essentially I can calculate the least number of coins possible to use, but not which coins they are. Here's the code and the little main method I'm using to drive it. Any suggestions of streamlining the algorithm itself would also be welcome.
public class DynamicCoinChange {
public static void main(String[] args) {
int[] denoms = {1, 6, 10, 25};
int numCoins = dynamicCoinChange(denoms, 18, 3);
System.out.println(numCoins);
}
public static int dynamicCoinChange(int[] denoms, int amt, int start) {
if (amt == 0 || start < 0) {
return 0;
} else if (amt == 1) {
return 1;
} else if (denoms[start] > amt ||
dynamicCoinChange(denoms, amt, start-1) <
(1 + dynamicCoinChange(denoms, amt-denoms[start], start)) &&
!(dynamicCoinChange(denoms, amt, start-1) == 0)) {
return dynamicCoinChange(denoms, amt, start-1);
} else {
return 1 + dynamicCoinChange(denoms,amt-denoms[start], start);
}
}
}
We need to know two pieces of information:
when a coin is chosen for the optimal solution
which coin was chosen for the optimal solution
According to your algorithm, we know that we select a coin whenever you return 1. We also know that the coin chosen at that the index of the coin chosen is start. Thus, we have information to solve this problem.
Since performance isn't a problem here, we will simply pass a coins parameter that is filled as the coins are selected.
public static int dynamicCoinChange(int[] denoms, int amt, int start, ArrayList<Integer> coins) {
if (amt == 0 || start < 0) {
return 0;
} else if (amt == 1) {
coins.add(1);
return 1;
} else if (denoms[start] > amt
// Note that these calls are not guaranteed to be in our solution
// Thus, we make a copy to prevent the calls from modifying our solution
|| dynamicCoinChange(denoms, amt, start-1, new ArrayList<Integer>(coins)) <
(1 + dynamicCoinChange(denoms, amt-denoms[start], start, new ArrayList<Integer>(coins)))
&& !(dynamicCoinChange(denoms, amt, start-1, new ArrayList<Integer>(coins)) == 0)) {
return dynamicCoinChange(denoms, amt, start-1, coins);
} else {
coins.add(denoms[start]);
return 1 + dynamicCoinChange(denoms,amt-denoms[start], start, coins);
}
}
Since this requires us to change our method signature, we must also modify our driver:
public static void main(String[] args) {
int[] denoms = {1, 6, 10, 25};
ArrayList<Integer> coins = new ArrayList<Integer>();
int numCoins = dynamicCoinChange(denoms, 7, 3, coins);
for (Integer coin : coins)
System.out.println(coin);
System.out.println(numCoins);
}
At the end of the recursive calls, coins should contain the list of coins chosen in chronological order.
The Minimum Change problem need not be programmed recursively. It can be programmed in a simpler iterative fashion.
int[] denoms = { 1, 6, 10, 25 };
int amt = 18;
double[] min = new double[ amt + 1 ];
for( int i = 1; i < min.length; i++ ) { // We're keeping min[ 0 ] as 0/
min[ i ] = Double.POSITIVE_INFINITY;
}
for( int i = 1; i <= amt; i++ ) {
for( int j = 0; j <= N - 1; j++ ) {
if( denoms[ j ] <= i && min[ i - denoms[ j ] ] + 1 < min[ i ] )
min[ i ] = min[ i - denoms[ j ] ] + 1;
}
}
Here, your solution would be in entry min[amt].