I am trying to calculate the minimum number of shots I need to take based on a given number of club lengths. You can also think of it as the minimum number of coins needed for a given change.
My code is
public static int golf(int holeLength, int[] clubLengths)
{
return golf(holeLength, clubLengths, 0);
}
public static int golf(int holeLength, int[] clubLengths, int shots)
{
if(holeLength==0)
shots+=0;
else if(holeLength<0)
shots=-1;
else
{
for(int i = 0; i<clubLengths.length; i++)
{
return golf(holeLength-clubLengths[i], clubLengths, shots+1);
}
}
return shots;
}
The issue here is that it only seems to give an answer based on the first number on the array. So for example, if I had {25,50,100} and I wanted to get to 100. Obviously, there is only a minimum of one shot required, yet the program will only calculate it using 25 and say 4. Similarly, if the first number is 21, then it will just give a stackoverflow.
Here is what is happening in your code: when the function runs the first loop, it gets the first element in clubLengths and returns right away without going to the next loop. You need to go through each possible clubs to use.
Here is my recursive solution:
Go through each club.
You can choose to use current club and use it again,
Or you can choose to use current club and use next club,
Or you can choose not to use current club and use next club.
I can implement this the following way:
public static int golf(int holeLength, int[] clubLengths) {
int[][] dp = int[clubLengths.length()][holeLength+1];
return golf(holeLength, clubLengths, 0, dp);
}
private static int golf(int holeLength, int[] clubLengths, int ind, int[][] dp) {
if (holeLength == 0) return 0;
if (holeLength < 0) return -1;
if (ind >= clubLengths.length()) return -1;
if (dp[ind][holeLength] != 0) return dp[ind][holeLength];
int rec1 = golf(holeLength-clubLengths[ind], clubLengths, ind, dp);
if (rec1 == -1) rec1 = Integer.MAX_VALUE;
else rec1++;
int rec2 = golf(holeLength-clubLengths[ind], clubLengths, ind+1, dp);
if (rec2 == -1) rec2 == Integer.MAX_VALUE;
else rec2++;
int rec3 = golf(holeLength, clubLengths, ind+1, dp);
if (rec3 == -1) rec3 = Integer.MAX_VALUE;
int result = Math.min(rec1, rec2);
result = Math.min(result, rec3);
if (result == Integer.MAX_VALUE) result = -1;
dp[ind][holeLength] = result;
return result;
}
Along with recursion, I have also added dp to optimize time complexity. As a result, the time complexity of my solution would be O(k*n) where k is holeLength and n is number of elements in clubsLengths. If you do not want dp and want just pure recursion, you can just remove all usages of dp from above and the code will still work, but slower.
Related
I have been trying to implement the recursive solution for the [Leetcode Minimum Number of Refueling Stops][1]. I came up with the solution below but it doesn't pass all test cases. I have put so much effort into this. I would appreciate a support.
Here is my code so far:
static int startTarget;
private static int helper(int target, int currentFuel, int start, int[][] stations, Map<String, Integer> memo) {
if (stations.length == 0)
return currentFuel < target ? -1 : 0;
if (stations[0][0] > currentFuel)
return -1;
String key = target + ", " + currentFuel;
if (memo.containsKey(key))
return memo.get(key);
if (currentFuel >= target)
return 0;
if (start == stations.length)
return -1;
int min = Integer.MAX_VALUE;
for (int i = start; i < stations.length; i++) {
int currentDistance = stations[i][0];
int initialDistance = startTarget - target;
int distance = currentDistance - initialDistance;
int fuel = stations[i][1];
if ((currentFuel - distance) >= 0) {
int result = helper(target - distance, currentFuel + fuel - distance, i + 1, stations, memo);
if (result >= 0 && result < min)
min = 1 + result;
}
}
min = (min == Integer.MAX_VALUE) ? -1 : min;
memo.put(key, min);
return min;
}
public static int minRefuelStopsBruteForce(int target, int startFuel, int[][] stations) {
startTarget = target;
int stops = helper(target, startFuel, 0, stations, new HashMap<>());
return stops != Integer.MAX_VALUE ? stops : -1;
}
Please I am only interested in the recursive solution.Thanks
[1]: https://leetcode.com/problems/minimum-number-of-refueling-stops/
Information wants to be free, so here you go :)
This solution uses the same approach as your solution, and it seems to work, so you can look at it to see what needs to be fixed with your code.
Sadly it is way to slow, so execution stops with "Time limit exceeded" at test case #115 that has approx 100 gas stations. So to solve the Leetcode task with recursion, a whole new way of thinking is needed.
public int minRefuelStops(int target, int startFuel, int[][] stations) {
Integer result = helper(-1, startFuel, target, stations, 0);
return result == null ? -1 : result.intValue();
}
private Integer helper(int currentStation, int currentFuel, int target, int[][] stations, int depth) {
int currentPos = currentStation == -1 ? 0 : stations[currentStation][0];
if (currentPos + currentFuel >= target) {
return 0;
}
Integer best = null;
for (int i = currentStation + 1; i < stations.length; i++) {
int stationPos = stations[i][0];
int stationFuel = stations[i][1];
// Check out station that we have not yet passed && we can reach
if (currentPos < stationPos && currentPos + currentFuel >= stationPos) {
// Drive to station
int fuel = currentFuel - (stationPos - currentPos);
// Fill up gas
fuel += stationFuel;
// Continue
Integer res = helper(i, fuel, target, stations, depth + 1);
if (res != null && (best == null || res < best)) {
best = res;
}
}
}
// Return "no can do" or return number of stations (adding *this* station)
return best == null ? null : best + 1;
}
You are pretty close but there are some errors. For example, it does not make sense to check station[0][0] all the time (second if statement). And the HashMap should not be needed.
I wrote a solution that I think works, but I'm not sure you want it. I think you can solve this on your own, which is a lot more awarding. I suggest you start from scratch, and give it another try. Here are a few hints:
I think you can take these if statements away:
if (stations.length == 0)...
if (stations[0][0] > currentFuel)...
if (memo.containsKey(key))...
I think it is easier to follow the code if you don't change "target" (currently you subtract distance). Instead, add a parameter that tells "helper" how far you have travelled (distance).
Give it another try, I'm sure you'll make it. If not, let me know, and I'll post my code :)
how do I transform this into a if else statement? im stuck in one part with the comment below. I would like to separate knapsack() into if statements.
static int max_val(int a, int b){
return(a>b)? a: b; //set value for a = 1 and b = 0
}
static int knapsack(int max_bag_limit, int[] weight, int[] value, int size){
if (size ==0 || max_bag_limit == 0){ //base case
return 0;
}
if(weight[size - 1] > max_bag_limit){
return knapsack(max_bag_limit, weight, value, size-1);
}
else{
return max_val(value[size-1]
+ knapsack(max_bag_limit - weight[size - 1],weight,value, size -1), //im stuck at this line
knapsack(max_bag_limit, weight, value, size -1) );
}
}
i tried to do it this way because i need to put it in a Jbutton.
else if(counter == 6){ //max_val compare knapsack A and Knapsack B
printCode(1);
if(knapsackA>knapsackB){
total = knapsackA;
}
else total = knapsackB;
}
else count = 1; // to avoid 0;
}
To allow more control over the algorithm, you need to break out one step to perform. This means that you need to think about what to do for a single step and what state you need to store so that you can perform the next step. A direct reimplementation of recursion can use an explicit Stack instead of relying on the call stack in the JRE.
I know this is a silly question,but I'm not getting this at all.
In this code taken from http://somnathkayal.blogspot.in/2012/08/finding-maximum-and-minimum-using.html
public int[] maxMin(int[] a,int i,int j,int max,int min) {
int mid,max1,min1;
int result[] = new int[2];
//Small(P)
if (i==j) max = min = a[i];
else if (i==j-1) { // Another case of Small(P)
if (a[i] < a[j]) {
this.max = getMax(this.max,a[j]);
this.min = getMin(this.min,a[i]);
}
else {
this.max = getMax(this.max,a[i]);
this.min = getMin(this.min,a[j]); }
} else {
// if P is not small, divide P into sub-problems.
// Find where to split the set.
mid = (i + j) / 2;
// Solve the sub-problems.
max1 = min1 = a[mid+1];
maxMin( a, i, mid, max, min );
maxMin( a, mid+1, j, max1, min1 );
// Combine the solutions.
if (this.max < max1) this.max = max1;
if (this.min > min1) this.min = min1;
}
result[0] = this.max;
result[1] = this.min;
return result;
}
}
Let's say the array is 8,5,3,7 and we have to find max and min,
Initial values of max and min=arr[0]=8;
First time list will be divided into 8,5
We call MaxMin with max=8 and min=8,since i==j-1,we will get max=8,min=5,
Next time list will be divided into [3,7],
min1=max1=arr[mid+1]=3,
We call MaxMin with max=3 and min=3.Since i is equal to j-1,we will get max=7,min=3,
Next the comparison is performed between max1,max and min1,min ,
Here is my confusion,
The values of max and max1 here is 8 and 7 respectively,but how???
We have not modified max1 anywhere,then how it will have a value 7,
As per my understanding,we had called MaxMin with max=3 and min=3 and then updated max=7 and min=3,but we had not returned these updated values,then how the values of max1 and min1 got updated,
I'm stuck at this,please explain.
Thanks.
It looks like you are updating 2 external values (not in this function) which are this.min and this.max
All you do is splitting in pieces of 1 or 2 elements and then update this.min and this.max, so you could also directly scan the array and check all int value for min/max. This is not really doing divide and conquer.
Here is a solution that really use divide and conquer :
public int[] maxMin(int[] a,int i,int j) {
int localmin,localmax;
int mid,max1,min1,max2,min2;
int[] result = new int[2];
//Small(P) when P is one element
if (i==j) {
localmin = a[i]
localmax = a[i];
}
else {
// if P is not small, divide P into sub-problems.
// where to split the set
mid = (i + j) / 2;
// Solve the sub-problems.
int[] result1 = maxMin( a, i, mid);
int[] result2 = maxMin( a, mid+1, j);
max1 = result1[0];
min1 = result1[1];
max2=result2[0];
min2=result2[1];
// Combine the solutions.
if (max1 < max2) localmax = max2;
else localmax=max1;
if (min1 < min2) localmin = min1;
else localmin=min2;
}
result[0] = localmax;
result[1] = localmin;
return result;
}
Frankly that blogger's code looks like a mess. You should have no confidence in it.
Take is this line early on:
if (i==j) max = min = a[i];
The values passed INTO the function, max and min, aren't ever used in this case, they are just set, and then lost forever. Note also if this line runs, the array result is neither set nor returned. (I would have thought that the compiler would warn that there are code paths that don't return a value.) So that's a bug, but since he never uses the return value anywhere it might be harmless.
The code sometimes acts like it is returning values through max and min (can't be done), while other parts of the code pass back the array result, or set this.max and this.min.
I can't quite decide without running it if the algorithm will ever return the wrong result. It may just happen to work. But its a mess, and if it were written better you could see how it worked with some confidence. I think the author should have written it in a more purely functional style, with no reliance on external variables like this.min and this.max.
Parenthetically, I note that when someone asked a question in the comments he replied to the effect that understanding the algorithm was the main goal. "Implementation [of] this algorithm is very much complex. For you I am updating a program with this." Gee, thanks.
In short, find a different example to study. Lord of dark posted a response as I originally wrote this, and it looks much improved.
Code
import java.util.Random;
public class MinMaxArray {
private static Random R = new Random();
public static void main(String[] args){
System.out.print("\nPress any key to continue.. ");
try{
System.in.read();
}
catch(Exception e){
;
}
int N = R.nextInt(10)+5;
int[] A = new int[N];
for(int i=0; i<N; i++){
int VAL = R.nextInt(200)-100;
A[i] = VAL;
}
Print(A);
Pair P = new Pair(Integer.MIN_VALUE, Integer.MAX_VALUE);
P = MinMax(A, 0, A.length-1);
System.out.println("\nMin: " + P.MIN);
System.out.println("\nMax: " + P.MAX);
}
private static Pair MinMax(int[] A, int start, int end) {
Pair P = new Pair(Integer.MIN_VALUE, Integer.MAX_VALUE);
Pair P_ = new Pair(Integer.MIN_VALUE, Integer.MAX_VALUE);
Pair F = new Pair(Integer.MIN_VALUE, Integer.MAX_VALUE);
if(start == end){
P.MIN = A[start];
P.MAX = A[start];
return P;
}
else if(start + 1 == end){
if(A[start] > A[end]){
P.MAX = A[start];
P.MIN = A[end];
}
else{
P.MAX = A[end];
P.MIN = A[start];
}
return P;
}
else{
int mid = (start + (end - start)/2);
P = MinMax(A, start, mid);
P_ = MinMax(A, (mid + 1), end);
if(P.MAX > P_.MAX){
F.MAX = P.MAX;
}
else{
F.MAX = P_.MAX;
}
if(P.MIN < P_.MIN){
F.MIN = P.MIN;
}
else{
F.MIN = P_.MIN;
}
return F;
}
}
private static void Print(int[] A) {
System.out.println();
for(int x: A){
System.out.print(x + " ");
}
System.out.println();
}
}
class Pair{
public int MIN, MAX;
public Pair(int MIN, int MAX){
this.MIN = MIN;
this.MAX = MAX;
}
}
Explanation
This is the JAVA code for finding out the MIN and MAX value in an Array using the Divide & Conquer approach, with the help of a Pair class.
The Random class of JAVA initializes the Array with a Random size N ε(5, 15) and with Random values ranging between (-100, 100).
An Object P of the Pair class is created which takes back the return value from MinMax() method. The MinMax() method takes an Array (A[]), a Starting Index (start) and a Final Index (end) as the Parameters.
Working Logic
Three different objects P, P_, F are created, of the Pair class.
Cases :-
Array Size -> 1 (start == end) : In this case, both the MIN and the MAX value are A[0], which is then assigned to the object P of the Pair class as P.MIN and P.MAX, which is then returned.
Array Size -> 2 (start + 1 == end) : In this case, the code block compares both the values of the Array and then assign it to the object P of the Pair class as P.MIN and P.MAX, which is then returned.
Array Size > 2 : In this case, the Mid is calculated and the MinMax method is called from start -> mid and (mid + 1) -> end. which again will call recursively until the first two cases hit and returns the value. The values are stored in object P and P_, which are then compared and then finally returned by object F as F.MAX and F.MIN.
The Pair Class has one method by the same name Pair(), which takes 2 Int parameters, as MIN and MAX, assigned to then as Pair.MIN and Pair.MAX
Further Links for Code
https://www.techiedelight.com/find-minimum-maximum-element-array-minimum-comparisons/
https://www.enjoyalgorithms.com/blog/find-the-minimum-and-maximum-value-in-an-array
Ok so my problem is basically, I have a matrix for example
010
101
111
just random 1s and 0s. So I have arrays that are rowcount and colcount, which count the number of ones in each row and column. So rowcount for this is {1,2,3} and colcount is {2,2,2}. Now in another method, I am given the arrays rowcount and colcount, and in that method, I am supposed to create a matrix with the counts in rowcount and colcount, but the end matrix can be different. Than the original. I think I'm supposed to exhaust all permutations until a matrix works. The base case must stay the same.
Note: Math.random cannot be used.
private static void recur(int[][] m, int[] rowcount, int[] colcount, int r, int c)
//recursive helper method
{
if(compare(m, rowcount, colcount)) //base case: if new matrix works
{
System.out.println();
System.out.println("RECREATED");
display(m, rowcount, colcount); //we're done!
System.exit(0);
}
else
{
int[] temp_r = new int[m.length];
int[] temp_c = new int[m[0].length];
count(m, temp_r, temp_c);
if(rowcount[r] > temp_r[r] && colcount[c] > temp_c[c])
m[r][c] = 1;
if(r+1 < m.length)
recur(m,rowcount,colcount,r+1,c);
if(rowcount[r] < temp_r[r] || colcount[c] < temp_c[c])
m[r][c] = 0;
if(c+1 < m[0].length)
recur(m,rowcount,colcount,r,c+1);
}
}
private static boolean compare(int[][] m, int[] rowcount, int[] colcount)
{
int[] temp_r = new int[m.length];
int[] temp_c = new int[m[0].length];
count(m, temp_r, temp_c);
for (int x = 0; x < temp_r.length; x++)
{
if(temp_r[x] != rowcount[x])
return false;
}
for (int y = 0; y < temp_c.length; y++)
{
if(temp_c[y] != colcount[y])
return false;
}
return true;
}
public static void count(int[][] matrix, int[] rowcount, int[] colcount)
{
for(int x=0;x<matrix.length;x++)
for(int y=0;y<matrix[0].length;y++)
{
if(matrix[x][y]==1)
{
rowcount[x]++;
colcount[y]++;
}
}
}
Well, I decided I'd implement a solution, but instead of Java (which you haven't actually specified the solution needs to be in), I'm going to use Groovy (which is Java based anyway)! I've tried to use Java syntax where possible, it's not hard to extrapolate the Java code from this (but it is much more verbose!)
Note:
*Generating a random bit matrix, not using Math.random()
*I'm storing my matrix in a string i.e. [[0,1],[1,0]] = "0110"
*My solution relies heavily, on converting Integers to/from BinaryStrings (which is essentially what your matrix is!)
// Generate random matrix
int colSize = 3;
int rowSize = 4;
String matrix = '';
for (int i = 0; i < rowSize; i++){
String bits = Integer.toBinaryString(System.currentTimeMillis().toInteger());
matrix += bits.substring(bits.length() - colSize);
Thread.sleep((System.currentTimeMillis() % 1000) + 1);
}
def (cols1,rows1) = getCounts(matrix, colSize)
println "matrix=$matrix rows1=$rows1 cols1=$cols1"
// Find match (brute force!)
int matrixSize = colSize * rowSize
int start = 0
int end = Math.pow(Math.pow(2, colSize), rowSize) // 2 is number of variations, i.e. 0 and 1
for (int i = start; i <= end; i++){
String tmp = leftPad(Integer.toBinaryString(i), matrixSize, '0')
def (cols2,rows2) = getCounts(tmp, colSize)
if (cols1 == cols2 && rows1 == rows2){
println "Found match! matrix=$tmp"
break;
}
}
println "Finished."
String leftPad(String input, int totalWidth, String padchar){ String.format('%1$' + totalWidth + "s", input).replace(' ',padchar) }
int[][] getCounts(String matrix, int colSize){
int rowSize = matrix.length() / colSize
int[] cols = (1..colSize).collect{0}, rows = (1..rowSize).collect{0}
matrix.eachWithIndex {ch, index ->
def intval = Integer.parseInt(ch)
cols[index % colSize] += intval
rows[(int)index / colSize] += intval
}
[cols,rows]
}
Gives output:
matrix=001100011000 rows1=[1, 1, 2, 0] cols1=[1, 1, 2]
Found match! matrix=001001110000
Finished.
Brute force search logic:
Given a rowcount of [1,2,3]
And a colcount of [2,2,2]
Iterate over all matrix combinations (i.e. numbers 0 - 511 i.e. "000000000" -> "111111111")
Until the new matrix combination's rowcount and colcount matches the supplied rowcount and colcount
OK, your question and comments indicate you are on the right track. The code itself is a bit messy and it has obviously gone through some iterations. That's not great, but it's OK.
You are right, I believe, that you have to 'exhaust' the recursion until you find a new result that matches the existing column/row counts. So, attack the problem logically. First, create a method that can compare a matrix with a row/column count. You call it 'compare(...)'. I assume this method you have already works ;-). This is the method that marks the end of the recursion. When compare returns true, you should return up the recursion 'stack'. You should not do a System.exit(...).
So, the basic rule of recursion, you need an input, output, a method body that contains an exit-condition check, and a recursive call if the condition is not met....
Your problem has a specific issue which complicates things - you need to make copies if the input matrix every time you go down a recursion level. Alternatively you need to 'undo' any changes you make when you come up a level. The 'undo' method is faster (less memory copies).
So, the process is as follows, start with an all-zero matrix. Call your recursive function for the all-zero start point.
int[][] matrix = new int[width][height];
int rpos = 0;
boolean found = recur(matrix, rowcount, colcount, 0, 0);
This is how it will be called, and found will be true if we found a solution.
The difference here from your code is that recur now returns a boolean.
So, our recur method needs to do:
1. check the current matrix - return true if it matches.
2. make meaningful changes (within the limits that we've added)
3. recursively check the change (and add other changes).
Your method does not have an output, so there's no way to escape the recursion. So, add one (boolean in this case).
The way this can work is that we start in the top left, and try it with that bit set, and with it unset. For each contition (set or unset) we recursively test whether the next bit matches when set, or unset, and so on.... :
private static boolean recur(int[][] m, int[] rowcount, int[] colcount,
int row, int col) {
if (compare(m, rowcount, colcount)) {
// our matrix matches the condition
return true;
}
if (row >= m.length) {
return false;
}
int nextcol = col + 1;
int nextrow = row;
if (nextcol >= m[row].length) {
nextcol = 0;
nextrow++;
if (nextrow > m.length) {
return false;
}
}
// OK, so nextrow and nextcol are the following position, and are valid.
// let's set our current position, and tell the next level of recursion to
// start playing from the next spot along
m[row][col] = 1;
if (recur(m, rowcount, colcount, nextrow, nextcol)) {
return true;
}
// now unset it again
m[row][col] = 0;
if (recur(m, rowcount, colcount, nextrow, nextcol)) {
return true;
}
return false;
}
The above code is just hand-written, it may have bugs, etc. but try it. The lesson in here is that you need to test your consitions, and you need a strategy....
I've come to a part in my code where I must generate a random number every time I press a button (r in this case). When I press this button, I want it to generate a number between 0 and n (3 in this case), but I don't want it to generate a number it previously generated. So I do not want the same number to be generated twice in a row. So 2 then 2 is bad. 2 then 0 then 2 is OK however.
I've looked around on here for questions similar to mine but none of them have really helped. Everyone else is generating once with the exception of numbers in an array or something. I'm constantly generating and I want to be able to detect the same number previous.
I am using the Random class, I have considered using the math.random class but that is between 0 and 1 so that isn't really too useful. Any help would be greatly appreciated, thanks! :D
Memorize what you generated last time; repeat generating until they are different
Say you want numbers 0-9
do
{
int n = Random.nextInt(10);
} while (n == prev) // prev is the number you generated previously
prev = n;
Since you have n possible values for the first, and only n-1 for the subsequent, just use randInt with a different argument depending on whether you're producing the first value or not. Trying to use randInt with the same arguments for all iterations will result in a non-flat distribution.
class NoAdjacentPRNG implements Iterator<Integer> {
private final Random rnd;
private final int range; // 3 to generate numbers in [0, 2).
private Integer last;
NoAdjacentPRNG(Random rnd, int range) {
this.rnd = rnd;
this.range = range;
}
public boolean hasNext() { return true; }
public Integer next() {
int n;
if (last == null) {
// The first time through, there are range possible values.
n = rnd.nextInt(range);
} else {
// There are only range-1 possible values given that the
// last is excluded.
n = rnd.nextInt(range - 1);
// Work around last.
if (n >= last) { ++n; }
}
last = n;
return n;
}
public void remove() { throw new UnsupportedOperationException(); }
}
You can do something like
int[] values = new int[360];
values[0] = random.nextInt(n+1);
for(int i = 0; i < values.length; i++) {
values[i] = random.nextInt(n);
if (values[i-1] == values[i]) values[i] = n;
}
You can even be super-simple:
public class NonRepeatingRandom extends Random {
private int last = -1;
#Override
public int nextInt(int i) {
int next = super.nextInt(i);
while ( next == last) {
next = super.nextInt(i);
}
return last = next;
}
}