converting while loop to recursion - java

I am having a problem with converting a while loop to a recursion ... the loop seems to work fine however I tried several times to turn it to recursion and what the method returns is the last (return c;) as 0 ... I mean how can you actually turn a while loop into a recursion? the program should count the numbers below 2 in the array
thats the main
public static void main(String[] args) {
double[] gpa = new double[]{2.5, 1.3, 1.3, 3.3, 1.2, 3.2, 4, 2.3, 3.1, 1.2};
int start = 0;
countGPA(gpa,start);
System.out.println(countGPA(gpa, start));
}
and thats the method
public static int countGPA(double[] gpas, int start) {
int L = gpas.length;
int c = 0;
int countGPA = c;
while (start < 10) {
if (start > 0 && start != L) {
if (gpas[start] < 2.0 && gpas[start] > 0) {
c++;
}
} else if (start == L) {
return 0;
} else if (start < 0 && start > L) {
return -1;
}
start++;
}
return c;
}

This looks like a simple recursion:
public int GPA(double[] gpas, int index){
if(index >= gpas.length) return 0;
if(0 < gpas[index] && gpas[index] < 2) return 1 + GPA(gpas, index + 1);
else return GPA(gpas, index + 1);
}
Just call it GPA(gpa, 1).
There is a lot of unnecessary comparisons in your method. Look at your uses of 10, L and start.
For example, suppose start = 0. No one of your ifs will enter. Better to start with 1. Look:
if (start > 0 && start != L) //start is 0 so this won't enter
else if (start == L) //start is 0 so this won't enter
else if (start < 0 && start > L) //start is 0 so this won't enter

There are three most important things about a recursive function/method:
The terminating condition.
The value with which the method/function is called recursively.
Where (before/after the recursive call) to process the parameter(s).
Do it as follows:
public class Main {
public static void main(String[] args) {
double[] gpa = new double[] { 2.5, 1.3, 1.3, 3.3, 1.2, 3.2, 4, 2.3, 3.1, 1.2 };
int start = 0;
System.out.println(countGPA(gpa, start));
}
public static int countGPA(double[] gpas, int start) {
return countGPA(gpas, start, 0);
}
public static int countGPA(double[] gpas, int start, int count) {
if (start >= gpas.length) {// Terminating condition
return count;
}
if (gpas[start] < 2.0 && gpas[start] > 0) {
return countGPA(gpas, ++start, ++count);// The recursive call
} else {
return countGPA(gpas, ++start, count);// The recursive call
}
}
}
Output:
4

Two important things to note when creating recursive methods.
You must include a base case, that when true stops the recursive calls and returns the values. If you don't have a base case, you'll run into a StackOverFlow exception.
In your scenario the recursion will stop when the index value is equal to the length of the array.
The method must call itself from within.
Anything that can be iterated over can also be a candidate for recursion.
Info on recursion: https://www.javatpoint.com/recursion-in-java
public int numbersBelowTwo(double[] gpas, int index){
//Base case, when this statement equates to true
//the recursions stops and returns the values.
if (index == gpas.length) return 0;
return gpas[index] < 2 ? 1 + numbersBelowTwo(gpas, ++ index) : numbersBelowTwo(gpas, ++index);
}

Related

Find the maximum length of contagious subarray with repeated element using recursive method with only list as the parameter

Problem:
Find the maximum length of contagious subarray with repeated elements.
eg:
[1 2 2 2 3 3 5 1 8] - answer is 3 since 2 repeated 3 times is the max repeated times.
[1 2] - answer is 1
[1 2 2 3 3] - answer is 2
But the recursive function should only have list as the argument. int findMaxContagiousRepeatedLength(List<Integer> list)
What I've tried:
class Answer
{
public static int findMaxContagiousRepeatedLength(List<Integer> nums, int currentCount, int latestNumber)
{
if (nums.isEmpty())
return 0;
if (nums.get(0) == latestNumber) {
return Math.max(currentCount+1, findMaxContagiousRepeatedLength(nums.subList(1, nums.size()), currentCount+1, nums.get(0)));
} else {
return findMaxContagiousRepeatedLength(nums.subList(1, nums.size()), 1, nums.get(0));
}
}
public static void main(String[] args)
{
Integer[] nums = { 1,2,1,1,1,1,1,2,3,2,3,1,2,2};
System.out.println("Max length: " +
findMaxContagiousRepeatedLength(Arrays.asList(nums), 0, nums.length == 0 ? -1 : nums[0]));
}
}
The above does work, but doesn't meet the requirement of argument restriction.
Please help me figure out if it's possible to have a solution where recursive function only have list as the argument.
Best solution
Use your Function
public static int findMaxContagiousRepeatedLength(List<Integer> nums, int currentCount, int latestNumber)
{
if (nums.isEmpty())
return 0;
if (nums.get(0) == latestNumber) {
return Math.max(currentCount+1, findMaxContagiousRepeatedLength(nums.subList(1, nums.size()), currentCount+1, nums.get(0)));
} else {
return findMaxContagiousRepeatedLength(nums.subList(1, nums.size()), 1, nums.get(0));
}
}
and make a second Function which calls your function with default parameters
public static int findMaxContagiousRepeatedLength(List<Integer> nums)
{
return findMaxContagiousRepeatedLength(Arrays.asList(nums), 0, nums.length == 0 ? -1 : nums[0]);
}
Now you can call the second function which calls the first function with default parameters!
First, this problem is best solved by just going through the list.
But if you must use recursion with List<Integer> as the only parameter you may use the below:
public static int findMaxContiguousRepeatedLength(List<Integer> nums) {
if (nums.isEmpty()) {
return 0;
}
Iterator<Integer> it = nums.iterator();
Integer start = it.next();
int len = 1, pos = 1;
while (it.hasNext()) {
Integer curr = it.next();
if (curr == start) {
pos++;
len++;
} else {
break;
}
}
return Math.max(len, findMaxContiguousRepeatedLength(nums.subList(pos,nums.size())));
}
If you're allowed to (temporarily) modify the list, the below approach would also work:
public static int findMaxContiguousRepeatedLength(List<Integer> nums) {
if (nums.isEmpty()) {
return 0;
}
// carve out repeated chunk from back
Integer back = nums.remove(nums.size() - 1);
int repeats = 1;
while(!nums.isEmpty() && nums.get(nums.size() - 1) == back) {
nums.remove(nums.size() - 1);
repeats++;
}
int res = Math.max(repeats, findMaxContiguousRepeatedLength(List<Integer> nums));
while(repeats) { // restore
repeats--;
nums.add(back);
}
return res;
}

Recursion sum numbers *with rule* - Recursion only

So the exercise is:
Using recursion only (no loops)
Find if there is sub ground of numbers that are equal to the given number in an array and follow the rule.
Let's say I have this array, I give the function a number for sum and it must adhere to this rule:
you cannot repeat the same number, and you can't sum 3 numbers in a row (can't do i+1 and i+2)
int[] a = {5,4,2,1,3};
So in this case:
num 8 = true (4+3+1) ( 5+3)
num 11 = false (4+5+2 are 3 but are three in a row) (5+2+1+3 also three in a row)
My attempt is:
public static boolean sumRule(int[] a , int num){
if (num == 0){
return true;
} else {
return sumRule(a,num,0,a.length);
}
}
private static boolean sumRule(int[] a, int num, int low,int high){
if(low >= high || low < 0){
return false;
}
if (a[low] == -1){
return false;
}
if(a[low] == num || num-a[low] == 0 ){
return true;
}
int temp = a[low];
a[low] = -1;
return sumRule(a,num,low,high) || sumRule(a,num-temp,low+3,high) || sumRule(a,num-temp,low+1,high) ;
}
But when I send 11 to this, it still returns true, anyone has an idea what am i missing here?
Thanks,
I have the full code answer below, and here's the explanation:
Essentially you need to break this problem down to a recurrence. What that means is, you look at the choice at each step (i.e. whether to use a number or not in the sum) and recursively calculate both options.
The base case:
If num == 0 then we know it's true. But if num != 0 and the array has length 0, then we know it's false
Recursive case:
We check if the first number in the array is less than or equal to num. If not, then we can't use it. So we do a recursive call with all the same parameters except the array is now the original array minus the first number
If we CAN use the number (i.e. a[0] <= num) then the true answer might use this or it may not use it. We make a recursive call for each case, and return true if either of the recursive calls return true.
The consecutive number rule:
This is easy to enforce. We add a parameter called 'left' which tells us the number of elements we can consecutively take from the beginning of the array. To start with, left is 2 because at most we can take 2 consecutive numbers. Then in the cases where we DO use the first number in the array in our sum, we decrement left. If we don't use the first number in the array, we reset left to 2. In the cases where left becomes 0, we have no choice but to skip the current number at the top of the array.
class Main {
public static void main(String[] args) {
int[] a = new int[] {5,4,2,1,3};
System.out.println(sumRule(a, 8));
System.out.println(sumRule(a, 11));
}
public static boolean sumRule(int[] a , int num){
if (num == 0){
return true;
} else {
return sumRule(a,num,2);
}
}
private static boolean sumRule(int[] a, int num, int left){
if (num == 0) {
return true;
}
if (a.length == 0) {
return false;
}
int[] a_new = new int[a.length-1];
for (int i = 1; i < a.length; i++) a_new[i-1] = a[i];
if (left == 0) {
return sumRule(a_new, num, 2);
}
boolean using_a0 = false;
if (a[0] <= num) {
using_a0 = sumRule(a_new, num-a[0], left-1);
}
boolean not_using_a0 = sumRule(a_new, num, 2);
return (not_using_a0 || using_a0);
}
}
Edit - A variation on the code above without copying the array:
class Main {
public static void main(String[] args) {
int[] a = new int[] {5,4,2,1,3};
System.out.println(sumRule(a, 8));
System.out.println(sumRule(a, 11));
}
public static boolean sumRule(int[] a , int num){
if (num == 0){
return true;
} else {
return sumRuleNoLoop(a,num,2,0);
}
}
private static boolean sumRuleNoLoop(int[] a, int num, int left, int startIdx){
if (num == 0) {
return true;
}
if (startIdx >= a.length) {
return false;
}
if (left == 0) {
return sumRuleNoLoop(a, num, 2, startIdx+1);
}
boolean using_a0 = false;
if (a[startIdx] <= num) {
using_a0 = sumRuleNoLoop(a, num-a[startIdx], left-1, startIdx+1);
}
boolean not_using_a0 = sumRuleNoLoop(a, num, 2, startIdx+1);
return (not_using_a0 || using_a0);
}
}
First thing you can add is a check to see not 3 numbers in a row being added. Also replacing a number in the array with -1 would have unintended side effects within recursive calls. Below is something I have. You can ignore the index param I have used to see the values used.
Explanation:
The recursive sumRule method divides the problem into two parts:
First part takes the value of current index and adds with the sum of values starting from next index.
Second part assumes, current value can’t be taken for the sum. It only checks if there is a sum within the subset starting from next value of the array.
In the method, lastIndex is keeping track of the index of last value picked up for the sum. So, in the first call the value is 0, 1 in second and so on.
(start - lastIndex <= 1 ? consecutive + 1 : 1) is to check whether value of consecutive should be increased or not. consecutive = 1 means, current value is added to the sum.
public static boolean sumRule(int[] a, int num) {
if (num == 0) {
return true;
} else {
return sumRule(a, num, 0, 0, 0, 0, "");
}
}
public static boolean sumRule(final int[] a, int num, int sum, int start, int consecutive, int lastIndex,
String index) {
if (consecutive == 3) {
return false;
}
if (sum == num) {
System.out.println(index);
return true;
}
if (start >= a.length) {
return false;
}
return sumRule(a, num, sum + a[start], start + 1, (start - lastIndex <= 1 ? consecutive + 1 : 1), start,
index + ", " + start) || sumRule(a, num, sum, start + 1, consecutive, lastIndex, index);
}
Here is my implementation. It contains comments explaining what the different parts do.
public class RecurSum {
/**
* Determines whether 'sum' equals 'target'.
*
* #param arr - its elements are summed
* #param sum - sum of some elements in 'arr'
* #param target - required value of 'sum'
* #param index - index in 'arr'
* #param consecutive - number of consecutive indexes summed to ensure don't exceed 3
* #param start - starting element in 'arr' which is used for back-tracking
*
* #return "true" if 'sum' equals 'target'
*/
private static boolean sumRule(int[] arr, int sum, int target, int index, int consecutive, int start) {
if (sum == target) {
return true;
}
else {
if (index >= arr.length) {
// if we have reached last element in 'arr' then back-track and start again
if (start < arr.length) {
return sumRule(arr, 0, target, start + 1, 0, start + 1);
}
// we have reached last element in 'arr' and cannot back-track
return false;
}
else {
consecutive++;
if (consecutive == 3) {
// skip 3rd consecutive element (because of the rule)
consecutive = 0;
return sumRule(arr, sum, target, index + 2, consecutive, start);
}
else {
if (sum + arr[index] > target) {
// recursive call but don't add current element of 'arr'
return sumRule(arr, sum, target, index + 1, 0, start);
}
// recursive call: add current element of 'arr' to 'sum' and proceed to next element
return sumRule(arr, sum + arr[index], target, index + 1, consecutive, start);
}
}
}
}
public static void main(String[] args) {
int[] arr = new int[]{5, 4, 2, 1, 3};
// initial call to recursive method with target = 11 (eleven)
System.out.println(sumRule(arr, 0, 11, 0, 0, 0));
// initial call to recursive method with target = 8
System.out.println(sumRule(arr, 0, 8, 0, 0, 0));
}
}

Sum odd numbers program

I'm writing a program where I'm supposed to make a method that calculates if the passed number is odd. For this method, I also need to check that passed number is > 0, and if not, return false.
I am also supposed to make a second method with two parameters (start and end, which represents a range of numbers) and the method is supposed to use a for loop to sum all odd numbers within that range. The parameter end needs to be greater than or equal to start and both start and end parameters have to be greater than 0.
If those conditions are not satisfied return -1 from the method to indicate invalid input.
This is the assignment:
Write a method called isOdd with an int parameter and call it number. The method needs to return a boolean.
Check that number is > 0, if it is not return false.
If number is odd return true, otherwise return false.
Write a second method called sumOdd that has 2 int parameters start and end, which represent a range of numbers.
The method should use a for loop to sum all odd numbers in that range including the end and return the sum.
It should call the method isOdd to check if each number is odd.
The parameter end needs to be greater than or equal to start and both start and end parameters have to be greater than 0.
If those conditions are not satisfied return -1 from the method to indicate invalid input.
I've tried for over an hour now but I'm not doing it correctly because my output is wrong. I've written down the expected results and my results below my code.
This is my code:
public static boolean isOdd(int number){
boolean status = false;
if(number < 0){
status = false;
} else if(number % 2 != 0){
status = true;
}
return status;
}
public static int sumOdd(int start, int end){
int sum = 0;
if((end < start) || (start < 0) || (end < 0)){
return -1;
}
for(int i = 0; i <= end; i++){
if((isOdd(i))){
sum += i;
}
}
return sum;
}
The expected result is:
System.out.println(sumOdd(1, 100));// → should return 2500
System.out.println(sumOdd(-1, 100)); // → should return -1
System.out.println(sumOdd(100, 100));// → should return 0
System.out.println(sumOdd(13, 13));// → should return 13 (This set contains one number, 13, and it is odd)
System.out.println(sumOdd(100, -100));// → should return -1
System.out.println(sumOdd(100, 1000));// → should return 247500
My result:
2500
-1
2500
49
-1
250000
First, your isOdd method only needs to return true if two conditions are met: the number must be greater than zero and it must be odd. That can be done with a single return and a boolean and. Like,
public static boolean isOdd(int number) {
return number > 0 && number % 2 != 0;
}
Second, your loop should start at start (not zero). But, I would then test if start is even. If it is, increment it before the loop. Then we know we have an initial value that is odd so we no longer need to test for oddness in the loop (we can increment by two instead). Like,
public static int sumOdd(int start, int end) {
if (end < start || start < 0 || end < 0) {
return -1;
}
int sum = 0;
if (!isOdd(start)) {
start++;
}
for (int i = start; i <= end; i += 2) {
sum += i;
}
return sum;
}
Which should be quite a bit more efficient.
Don't declare variables at the begging of your method, only create them when they are needed. As pointed out by Jordan the problem is with for loop index, it should start from start, not 0:
public static boolean isOdd(int number) {
if (number < 0) {
return false;
}
return number % 2 != 0;
}
public static int sumOdd(int start, int end) {
if ((end < start) || (start < 0) || (end < 0)) {
return -1;
}
int sum = 0;
for (int i = start; i < end; i++) {
if (isOdd(i)) {
sum += i;
}
}
return sum;
}

Collatz Conjecture Method - Java

I am just learning to use methods in Java. I am trying to use a method to output the number of steps it takes to get to 1 using the collatz conjecture. Can anyone help me understand better how to execute the method? This is what I have so far:
public static void main(String[] args) {
collatz();
}
public static void collatz(int n) {
n = 20;
int i = 0;
if (n == 1) {
} else if (n % 2 == 0) {
n = (n / 2);
} else {
n = (3 * n + 1);
}
i++;
System.out.println(i);
}
This won't work because "i" is only going to be changed at the end of your code and you are not using recursion or any sort of loop in your code. So, even if it did compile, it won't give the right answer.
This is the recursive way that I've done for you.
public class Cycle {
static int cycle2 (int num) {
if (num == 1) {
return 0;
} else {
if (num % 2 > 0) {
return 1 + cycle2(num * 3 + 1);
} else {
return 1 + cycle2(num / 2);
}
}
}
public static void main(String[] args) {
int num = 14;
System.out.println(cycle2(num));
}
}
As I understand it you're asking about the syntax (rather than the algorithm itself), so here's another version of the above:
public static void main(String[] args) {
// collatz has to be called with a value or it won't compile
collatz(20);
}
public static void collatz(int n) {
int i = 0;
// The following has to occur inside a loop or it'll only occur once
while (n > 1)
{
// The following is what's known as "ternary form" - if the first statement is true, it'll assign the first value. Otherwise it assigns the first value.
// For example,
// int a = (1 == 2 ? 10 : 20);
// will equal 20
n = (n % 2 == 0 ?
(n / 2) : // This value will be assigned if n is even
(3 * n + 1)); // This value will be assigned if n is odd
i++;
}
System.out.println(i);
}
I know this question was asked a long time ago and i had similar problem so this is my solution:
public class Collatz {
public static void main(String[] args) {
collatz();
}
/*If you have (int n) inside method then
when you are calling collatz() you need to have
value inside parentheses-collatz(20), or do simply like I did.
Also you need while loop! It will loop n (20) untill finaly get 1.
Otherwise your code will execute only once
and you will have as a result 1 step to complete instead of 7*/
private static void collatz() {
int n = 20;
int i = 0;
while (n != 1) {
if (n % 2 == 0) {
n = (n / 2);
} else {
n = (3 * n + 1);
}
i++;
}
System.out.println(i);
}
}

Boolean Satements

public class A4work
{
private static int fibonacci(int n) {
if (n <= 1) {
return n;
}
{
return fibonacci(n - 1) + fibonacci(n - 2);
}
}
private static boolean isAfibonacci(int a) {
int x = 0; //sequence number
int c = 0; //number in fib sequence
while (a <= c) {
c = fibonacci(x);
x++;
}
if (a == c) {
return true;
} else {
return false;
}
}
public static void main(String[] args) //called a method signiture
{
System.out.println("The 5th Square pyramidal number is " + isAfibonacci(3));
}
}
I think I have the code right, but it keeps on returning false. I'm using it to decide if a number is in the fib sequence or not.
Thanks for the help
When you use System.out.println("The 5th Square pyramidal number is "+ isAfibonacci(3) );, a in your isAfibonacci(); method becomes 3. Now look at your code knowing that.
while(3 <= 0) //replaced a with 3 here and c with 0 for visualization
{
...
}
A non-negative, non-zero integer will never be less than or equal to 0, therefore, will always result in false.
If your input a is 5, for example, you will have:
int c = 0; //number in fib sequence
while (a <= c) { ... }
The while loop will never run since 5 <= 0 is false. So a == c will always be false for any a greater than zero.
I think you want to stop iterating when c is greater than or equal to a, so the correct condition would be
while (c < a) { ... }

Categories

Resources