Can anyone help me understand this piece of code? - java

Can anyone please help me understand this code?
This code is used to solve this problem.
You are playing a game on your cellphone. You are given an array of length n, indexed from 0 to n−1. Each element of the array is either 0 or 1. You can only move to an index which contains 0. At first you are at the 0th position. In each move you can do one of the following things:
Walk one step forward or backward.
Make a jump of exactly length m forward.
That means you can move from position x to x+1, x−1 or x+m in one move. The new position must contain 0. Also you can move to any position greater than n-1.
You can't move backward from position 0. If you move to any position greater than n−1, you win the game.
Given the array and the length of the jump, you need to determine if it's possible to win the game or not.
n = sc.nextInt();
m = sc.nextInt();
field = new int[n];
for (int i = 0; i < n; i++) {
field[i] = sc.nextInt();
}
if (makeMove(0, new LinkedList<Integer>()))
System.out.println("YES");
else
System.out.println("NO");
.
.
.
private boolean makeMove(int position, List<Integer> prevPositions)
{
if (prevPositions.contains(position))
return false;
prevPositions.add(position);
if (position < 0) return false;
else if (position >= n) return true;
else if (field[position] == 1) return false;
else {
return makeMove(position + m, prevPositions) ||
makeMove(position + 1, prevPositions) ||
makeMove(position - 1, prevPositions);
}
}
input: 6 2
0 0 0 1 0 0
Output: Yes
input: 6 2
0 0 1 1 0 0
Output: No

So, I am assuming that you understand the concept of recursion, which is calling a method within itself, if not you may want to look it up.
The first section of code is very simple. It initializes the move length m and the array of length n and populates it with random binary digits.
The makeMove method goes through a few base cases to see if a branch of recursion has failed or succeeded.
1.) if (prevPositions.contains(position))
return false;
prevPositions.add(position);
After making a move, this code checks whether you have already gotten to this position. If you have, it returns false because this case has already been known to be false, otherwise the method would have already returned true.
2.) if (position < 0) return false;
else if (position >= n) return true;
else if (field[position] == 1) return false;
-You can't have a negative position, so that returns false.
-If your position is greater than n then you win, so return true
-You can't move to a position that contains a non-zero digit, so return false
3.) return makeMove(position + m, prevPositions) ||
makeMove(position + 1, prevPositions) ||
makeMove(position - 1, prevPositions);
This code makes recursive calls to other moves from possible positions and returns true if any of these calls are true. Since you can leap to position+m, then it makes sense that if makeMove(position+m, prevPositions) is true, then makeMove(position, prevPositions) is also true. Similarly you can move to position+1 and position-1 so calls to makeMove of these positions should return the same value as makeMove of your original position. Hope this made sense!

This solution works fine. Please try this. you need to pass, the element array length and the jump values.
public static boolean decideMove(int[] elements, int length, int jump){
boolean result = false;
boolean makeMove = true;
int currentPosition = 0;
while(makeMove){
if (currentPosition + jump > length-1){
return true;
}
if(elements [currentPosition + jump] == 0){
currentPosition = currentPosition + jump;
if (currentPosition + jump > length-1){
return true;
}
}
if (elements[currentPosition + 1] == 0){
currentPosition = currentPosition + 1;
if (currentPosition + jump > length-1){
return true;
}
}
if(elements[currentPosition +1] ==1 && elements[currentPosition + jump]==1){
if(elements[currentPosition - 1]==0){
currentPosition = currentPosition - 1;
} else{
return false;
}
}
}
return result;
}

Related

Java recursive calls

I want to build a code to go over any sequence of 0 and 1 and calculate how many different ways it can pass through the number just "jumping" between the '1's. Also it can jump no more than 3 digits per time.
For example, number 100110101 it could be like:
1xx1xx1x1 or 1xx11x1x1 (passing through all the '1').
Another example could be 1011011101:
1x11x111x1 (passing through all '1') or 1xx1x111x1 or 1x1xx1x1x1 and so on...
The important is not to jump more than 3 digits.
And the number will always start and finish with 1 as well.
I've got the following code and I think it is working.
public int calculate(String number){
if(number.length()<3){ //left fill with 0
if(number.length()==2) number = "0" + number;
else number = "00" + number;
}
if(number.length() == 3){ //for 001, 101, 011, 111
if (number.equalsIgnoreCase("111")) return 2; //2 possible ways
else return 1; //any other combination will have just one way
}
String aux = number.substring(1,4);//take the 3 next digits
//recursive calls to calculate it
if (aux.equalsIgnoreCase("001")) return calculate(number.substring(3, number.length()));
else if (aux.equalsIgnoreCase("010")) return calculate(number.substring(2, number.length()));
else if (aux.equalsIgnoreCase("011")) return calculate(number.substring(2, number.length())) + calculate(number.substring(3, number.length()));
else if (aux.equalsIgnoreCase("100")) return calculate(number.substring(1, number.length()));
else if (aux.equalsIgnoreCase("101")) return calculate(number.substring(1, number.length())) + calculate(number.substring(3, number.length()));
else if (aux.equalsIgnoreCase("110")) return calculate(number.substring(1, number.length())) + calculate(number.substring(2, number.length()));
else if (aux.equalsIgnoreCase("111")) return calculate(number.substring(1, number.length())) + calculate(number.substring(2, number.length())) + calculate(number.substring(3, number.length()));
return 0;
}
The question is: I also wanna make sure that it is not allowed to jump 3 digits twice in a row. Something like 1xx1xx1 is not allowed. However since I'm using recursive calls I don't know if that's possible.
One way to prevent jumping 3 digits twice in a row is to pass extra state information to calculate(); the extra data you pass would be a boolean indicating whether or not the last jump was of length 3. Then in your initial call to calculate(), just make sure to indicate that the last jump was not of length 3 (so the first jump is allowed to be of length 3).
private static int countPossibilities(String inputString) {
final char validChar = '1';
final char maxDistance = 3; // max consecutive jumps. eg: maxDistance for '1xxx1' is 3.
if (inputString.length() == 1) {
return 1;
}
var indexForMaxPossibleJump = Math.min(maxDistance + 1, inputString.length() - 1);
if (inputString.charAt(indexForMaxPossibleJump) != validChar) {
indexForMaxPossibleJump = inputString.substring(0, indexForMaxPossibleJump).lastIndexOf(validChar);
}
// No jumps possible.
if (indexForMaxPossibleJump == 0) {
return 0;
}
int finalCount = 0;
var remainingString = inputString.substring(indexForMaxPossibleJump);
var maxJumpingString = inputString.substring(1, indexForMaxPossibleJump);
// calculate count if we are not jumping to max distance. i.e., taking intermediate step on 1.
for (var i = 0; i < maxJumpingString.length(); i++) {
if (maxJumpingString.charAt(i) != validChar) {
continue;
}
var countOfString = countPossibilities(maxJumpingString.substring(i) + remainingString);
finalCount += countOfString;
}
// calculate count if we are jumping to max distance.
var countOfRemainingString = countPossibilities(remainingString);
finalCount += countOfRemainingString;
return finalCount;
}

Assessing whether 2 inputted variable values can sum to a inputted value

I'm working on a small program where a method takes 3 int's bigCount smallCount and goal.
These variables are supposed to represent the number of bags of flour in 2 sizes, the bigCount weight value is 5 kilos per bag, smallCount weight value is 1 kilo per bag and goal is the goal weight of the box that would contain the bags.
for example bigCount = 1, bigCount = 1, smallCount = 0, goal = 4
Should return a value of false since bigCount is given the value of 1 and 1 value in bigCount is representative of a 5 kilo bag and thus the bags that you have would never fit into a box with the weight requirement of 4.
At first, I tried to create a bunch of if and else if statements that would return a true value if the values of bigCount and smallCount could be added in a combination to sum to the weight given in the goal variable.
I feel like there is a much smarter way to go about this but I can't figure out an algorithm that could simply wrap all this up without all these if and else if statements. Currently, the logic for some of these if statements is incorrect and not catching all the scenarios to make it work properly.
public static boolean canPack(int bigCount, int smallCount, int goal){
boolean isPackable = false;
int bigBKilo = bigCount*5;
int smallBKilo = smallCount*1;
int remain5 = goal %5;
int remainTest = 6 %5;
int sum = bigBKilo+smallBKilo;
if( bigCount < 0 || smallCount < 0 || goal <0){
isPackable = false;
}else{
if(remain5 > 0 && remain5 <= smallCount && smallCount >= goal) {
isPackable = true;
}
else if(remain5 == 0 && bigCount > 0){
isPackable = true;
}
else if(bigCount == 0 && smallCount >= goal){
isPackable = true;
}
else if(smallCount ==0 && remain5 == 0){
isPackable = true;
}
else if(sum == goal){
isPackable = true;
}
else if(bigBKilo < goal && remain5 <= smallCount){
isPackable = true;
}
else if(bigCount == 0 && smallCount < goal){
isPackable = false;
}
else{
isPackable = false;
}
}
return isPackable;
}//end method
One possible way to solve the problem with some math is as follows:
Pick the biggest bag
Try to fit as many of them in the box as possible (limited by box goal and amount of bags available) - by doing some math
Calculate amount of space remaining in the box after those operations
Pick second biggest bag
Try to fit as many of those in the remaining space as possible
Repeat until you run out of bags or remaining space is 0
I think you should be able to implement this algorithm on your own.

Find max rating(number) in an array where we cannot skip over 1 or more consecutive number in array

we have an array of ratings, we have to find the max rating in such a away that we cannot skip 1 or more consecutive rating in an arrray
Example-1: {9,-1,-3,-4,-5} output = 9 + -1 + -4 = 4
Explanation: I took 9 the we have to took -1 or -3 we cannot jump to -4 directly as we cannot skip 1 or more consecutive number.
Example-2: {-1,-2,-3,-4,-5} output = -2 + -4 = -6
Example-3: {-3,2,-4,-1,-2,5} output = 2 + -1 + 5 = 6
Example-4: {9,-1,-3,4,5} output = 9 + -1 + 4 + 5 = 17
I tried below code but it is working in case of example: 2,3,4 but not for example 1 similarly failing for other scenario.
static int maximizeRatings(int[] ratings) {
int current = 0;
boolean result = false;
for(int j=0; j<ratings.length;j++){
if(ratings[j]<0){
result = true;
}else{
result = false;
}
}
if(result){
return allnegatine(ratings);
}
for(int i=0; i<ratings.length;i++){
if(i == ratings.length-1){
if(ratings[i] > 0)
current += ratings[i];
}else{
if(ratings[i] >0 && ratings[i+1]>0){
current = ratings[i]+ratings[i+1];
i++;
}
if(ratings[i] > ratings[i+1]){
current += ratings[i];
}else{
current += ratings[i+1];
i++;
}
}
}
return current;
}
private static int allnegatine(int[] ratings) {
int current =0;
for(int i=0; i<ratings.length;i++){
if(ratings.length%2==0){
if(i%2 == 0)
current += ratings[i];
}else{
if(i%2!=0)
current += ratings[i];
}
}
return current;
}
not getting excepted out for some scenarios like example 1 I am getting -6 instead of 4, I am trying to get proper code which will pass all scenarios. Thank you
This is a dynamic programming problem.
Let dp[i] be the max ratings which can be achieved considering only the part of the array that starts at zero, ends at i, and includes ratings[i].
dp[0]=ratings[0]
dp[1]=max(ratings[1],ratings[0]+ratings[1])
dp[i]=max(dp[i-1],dp[i-2])+ratings[i]
Answer: max(dp[n-1],dp[n-2]) where n is the size of the ratings array.
Also you can chose to do away with dp array and maintain 2 variables for dp[i-1] and dp[i-2].
this is typical recursion problem (as long as the input array is reasonably long). You should go thru items and try all possible combinations and then pick the best one.
Because it looks like typical school work I am not sure if I should paste my solution. You should figure it out yourself or at least understand what's going on to be able to implement it yourself next time.
public class RatingService {
public int calculate(List<Integer> input) {
return recursion(input, true, 0);
}
private int recursion(List<Integer> sublist, boolean canSkip, int sum) {
if (sublist.isEmpty()) {
return sum;
}
int skippedSum = Integer.MIN_VALUE;
int notSkippedSum;
Integer integer = sublist.get(0);
if (canSkip) {
skippedSum = recursion(sublist.subList(1, sublist.size()), false, sum);
}
notSkippedSum = recursion(sublist.subList(1, sublist.size()), true, integer + sum);
return skippedSum > notSkippedSum ? skippedSum : notSkippedSum;
}
}
I think you are doing the mistake while checking for all negative numbers in for loop. If the last element in the array is negative then the 'result' variable will be true means that all array is negative but actually its not.
You have to replace the for loop by :
for(int j=0;j<ratings.length;j++){
if(ratings[j]<0){
result=true;
}
else{
result = false;
break;
}
}
It will break the for loop at the index where it founds any positive number i-e: all elements of array are not negative.

Binary Search 2D array - Java

I am stuck on the following question:
Given a int two-dimensional matrix mat of size n2 where n = 2k, search for an integer k.
The matrix's rows and columns are sorted.
If we split the matrix in quarters, each quarter is also sorted. For example, given this matrix:
-4 -2 5 9
2 5 12 13
13 20 25 25
22 24 49 57
If we split it into quarters, we can see that all of the numbers in the first quarter are equal or less than numbers in the second quarter.
In order to obtain an efficient algorithm, I thought of making a recursive binary search in on the two dimensions but it fails to search for 2 on the previous matrix.
Here's the code:
public static boolean find(int[][] mat, int x){
return find2(mat, x, 0, mat.length-1,0, mat.length-1);
}
private static boolean find2(int[][] mat, int x, int lorow, int hirow,int locol,int hicol){
if(mat.length==0) return false;
if(lorow>hirow || locol>hicol) return false;
int midrow=(lorow+hirow)/2;
int midcol=(locol+hicol)/2;
if(mat[midrow][midcol] == x ) return true;
else if(mat[midrow][midcol] < x)
return find2(mat,x,lorow,midrow,midcol+1,hicol) || find2(mat,x,midrow+1,hirow,locol,midcol) || find2(mat,x,midrow+1,hirow,midcol+1,hicol);
else
return find2(mat,x,lorow,midrow,locol,midcol-1) || find2(mat,x,midrow,hirow,locol,midcol-1) || find2(mat,x,midrow+1,hirow,midcol+1,hicol);
}
Please advise.
Your mistake is at here in your code.
else
return find2(mat,x,lorow,midrow,locol,midcol-1) || find2(mat,x,midrow,hirow,locol,midcol-1) || find2(mat,x,midrow+1,hirow,midcol+1,hicol);
Here in first two functions, You are removing middle column from your search space. You need to include it as element can be present at the middle column. Another mistake is in the last call find2(mat,x,midrow+1,hirow,midcol+1,hicol).
If your search element is smaller than the middle element, You should choose top-left quadrant of the middle element and ignore the bottom-right quadrant. You have mistakenly considered here bottom-right quadrant over top-left quadrant.
After making changes accordingly the return function in else looks like:
return find2(mat,x,lorow,midrow,locol,midcol) || find2(mat,x,lorow,midrow,midcol+1,hicol) ||find2(mat,x,midrow+1,hirow,locol,midcol);
This solved the problem and it returns true for -2.
Updated Code:
private static boolean find2(int[][] mat, int x, int lorow, int hirow,int locol,int hicol){
if(mat.length==0) return false;
if(lorow>hirow || locol>hicol) return false;
if(lorow==hirow && locol==hicol && mat[lorow][locol]!=x)
return false;
int midrow=(lorow+hirow)/2;
int midcol=(locol+hicol)/2;
if(mat[midrow][midcol] == x ) return true;
else if(mat[midrow][midcol] < x)
return find2(mat,x,lorow,midrow,midcol+1,hicol) || find2(mat,x,midrow+1,hirow,locol,midcol) || find2(mat,x,midrow+1,hirow,midcol+1,hicol);
else
return find2(mat,x,lorow,midrow,locol,midcol) || find2(mat,x,lorow,midrow,midcol+1,hicol) ||find2(mat,x,midrow+1,hirow,locol,midcol);
}
If your matrix row and column are sorted you can use below code.
public int search(int mat[][], int n, int x) {
int i = 0, j = n - 1;
while (i < n && j >= 0) {
if (mat[i][j] == x) {
System.out.println("Found at" + i + j);
return 1;
}
if (mat[i][j] > x)
j--;
else // if mat[i][j] < x
i++;
}
System.out.println("not Found at");
return 0;
}

If statement for recordStrokes method

The method is to record the number of strokes a player took when completing a hole. The method returns true when strokes are successfully recorded. There are 2 caveats: (1)the hole must be recorded in order and must start with 1. If a hole is received out of order, the score is not recorded and false is returned (2)The hole number must also be valid. You can't record a score for a hole that is less than 1 or greater than the number of holes on the course. Code gives a java.lang.NullPointerException. What does this mean and how do i fix it
Note: holesPlayed is an instance variable assigned the value of 0
Here is what i have:
public boolean recordStrokes(int holeNumber, int strokes) {
if ((holeNumber >= 1) && (holeNumber <= Course.NUM_OF_HOLES)
&& (holeNumber == holesPlayed + 1)) {
scores[holeNumber -1] = strokes;
holesPlayed = holesPlayed + 1;
return true;
} else {
return false;
}
}
When holeNumber 1 is handed in, holesPlayed is 0, so this fails: holeNumber <= this.holesPlayed.

Categories