Recursion sum numbers *with rule* - Recursion only - java

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));
}
}

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;
}

Finding which matrix row has the highest sum java

I'm trying to write a recursive non-static method that for each given matrix will return the row number that has the highest total sum. I am not allowed to use static method and for loops (in any methods I write).
I think the solution is using three methods:
(private) count the total sum of a given row.
(private) compare total sum of row i with total sum of i+1 using method #1
(public) check that the matrix has more than one row and apply #2 on row 0.
I feel like I overcomplicate things here with my way of solving this problem. If anyone willing to suggest me better algorithm I'll be glad to try.
Anyway, I believe I'm ok with #1 and #3. My problem is with #2. I don't know how to set a row number variable:
public class Matrix {
private int[][] _mat;
public Matrix(int sizeRow, int sizeCol) {
_mat = new int[sizeRow][sizeCol];
}
private int maxRow(int row) { //Recursive method #2: comparing sum of i and i+1
int rowNumber;
if (row <= _mat.length) {
if (rowSum(row, 0) > rowSum(row+1,0)) {
rowNumber = row;
return maxRow(row+1);
}
else {
return rowNumber;
}
}
else {
return rowNumber;
}
}
..
public int maxRow() {..} //Recursive method #3
private int rowSum(int i, int j) {..} //Recursive method #1
}
My problem is with the var rowNumber. It has not been initialised and if I will initialise it it will be set to 0 each time I recall the method.
I have found exactly the same question here but the method suggested is static and receives array.
If you need to return the index of the row with maximum sum, you can do the following:
private int maxRow(int current_index, int max_index) {
if (current_index == _mat.length) {
return max_index;
} else if (sumRow(current_index) > sumRow(max_index)) {
return maxRow(current_index+1, current_index);
} else {
return maxRow(current_index+1, max_index);
}
}
maxRow(1, 0); //method call
The first argument current_index stores the index that you are currently testing, while argument max_index stores the visited index with maximum sum until now.
The first clause ensures that you return whatever index had the maximum sum value once you reach the end of the array.
The second clause updates max_index once you find a row with sum higher than what you had before.
The third clause just iterates to the next row when the above doesn't happen.
You can call the method with current_index=1 and max_index=0 so you don't need to initialize max_index with an invalid value.
If you want to improve performance, you can also add a new argument max_value to store the current max sum, so you don't need to call it at every recursive call.
This is an example of how you can retrieve the index of the row with the highest sum.
public class MaxRowFromArray {
private final int[][] values;
public MaxRowFromArray(int[][] values) {
this.values = values;
}
private int sumOfRow(int[] row, int rowIndex, int sum) {
if (rowIndex > row.length - 1) {
return sum;
}
return sumOfRow(row, rowIndex + 1, sum + row[rowIndex]);
}
private int highestRow(int column, int highestIndex, int highestRow) {
if (column > values.length - 1) {
return highestIndex;
}
int sumOfRow = sumOfRow(values[column], 0, 0);
if (sumOfRow > highestRow) {
return highestRow(column + 1, column, sumOfRow);
}
return highestRow(column + 1, highestIndex, highestRow);
}
public int highestRow() {
int highest = highestRow(0, 0, -1);
if (highest == -1) {
throw new IllegalStateException("No row can be found with the highest sum.");
}
return highest;
}
}
Test
public static void main(String[] args) {
MaxRowFromArray max = new MaxRowFromArray(new int[][] {
{ 1 },
{ 1, 2 },
{ 1, 2, 3 },
{ 1, 2, 3, 4}
});
int expectedHighest = 3;
int highestIndex = max.highestRow();
if (highestIndex != expectedHighest) {
throw new AssertionError(String.format("Highest index %s was not the expected highest %s.",
highestIndex, expectedHighest));
}
System.out.println("Highest: " + highestIndex);
}

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;
}

Divisors inside an array

I need to write a method that takes an array of integers and checks for every element if all its divisors (except the number itself and 1) are present in this array. If yes, the method will return true.
For example, the following array will return true:
4,5,10,2
I can't think of something efficient enough to be implemented. Could you guys help me out here?
I've been thinking to iterate through every element in the array, search for all of its divisors, put them on array, return the array and then compare to the elements in the original array.
This is a possible solution and it could work but I want to know of other possible solutions.
EDIT: Here is a code I've came up with but it is super slow. Could you guys help me optimise it a little bit?:
import java.util.Arrays;
public class Divisors {
public static void main(String[] args) {
int[] numbers = { 4, 5, 10, 2 };
boolean flag = true;
for (int num : numbers) {
if (num % 2 != 0) {
for (int subNum = 1; subNum < num / 2; num += 2) {
if(num%subNum == 0 && subNum != 1) {
if(!Arrays.asList(numbers).contains(subNum)) {
flag = false;
}
}
}
} else {
for (int subNum = 1; subNum < num / 2; num++) {
if(num%subNum == 0 && subNum != 1) {
if(!Arrays.asList(numbers).contains(subNum)) {
flag = false;
}
}
}
}
}
System.out.println("Result is: "+flag);
}
}
I think the following alogorithm solves your need. I have tested it on a few cases and it seems to work.
For example the array:
int[] set = {2, 3, 4, 5, 7, 10, 11, 15, 18, 35};
executes instantly giving the answer "true". Try removing the 7 which will give the answer "false".
You call it thus:
reduce(set, 0, 0)
The principle used is to iterative recursively through the array, reducing the array through factorization of the array by each element. If you find an element which is smaller than the last factor, it means it can't be factored. This only works if the array is sorted. Once you reach the end of the array, you know all elements have been factored.
private static boolean reduce (int[] set, int index, int factor) {
// NOTE: set must be a sorted set of integers
if (index == set.length) {
return true;
} else {
int divisor = set[index];
if (divisor != 1) {
if (divisor < factor) return false;
for (int i = index; i < set.length; i++) {
while ((set[i]%divisor) == 0) {
set[i] = set[i]/divisor;
}
}
return reduce(set, index+1, divisor);
} else {
return reduce(set, index+1, factor);
}
}
}
See if it works, let me know if you run into any problems.
1.Iterate through every element in the array
2. Find in for loop its divisor
3. While doing 2), check for every divisor if it is contained in the array. If false - return false.

A recursive method to check pattern in an array

I'm trying to write a recursive method in Java that will take two arrays of int and return true/false if the first array represent a pattern of the second array, in that way - (the pattern array accept 0, 1 or 2. 0 represent one or two digits number, 1 represent one digit numbers and 2 represent two digits numbers. so if I send {2, 3, 57} and {1, 0, 2} it will return true. if i put {2, 555, 57} and {1, 0, 2} it will return false. also, if i put {2,3,573**,4,34,35}** and {1, 0, 2} i still need to get true, since part of the array represnt the pattern.
i came up with this:
private static boolean match(int [] a, int [] pattern, int i, int j, int c, int subArr)
{
if(a.length < pattern.length)
return false;
else if(pattern.length == 0)
return true;
else if(pattern.length == a.length && check(a, pattern, i, j))
return true;
else if(check(a, pattern, i++, j++))
{
return check(a, pattern, i, j);
}
else return false;
}
private static boolean check(int [] a, int [] pattern, int i, int j)
{
if(pattern[j] == 1 && (checkDigits(a[i]) == 1))
{
return true;
}
else if(pattern[j] == 2 && checkDigits(a[i]) == 2)
{
return true;
}
else if(pattern[j] == 0 &&(checkDigits(a[i]) == 1 || checkDigits(a[i]) == 2 )){
return true;
}
else return false;
}
private static int checkDigits(int k){
int length = (int)(Math.log10(k)+1);
return length;
}
the match method is doing all the checks. the check methode is checking the pattern and checkDigits the number of digits.
My problem is with 3 digits numbers. if i put for exemple { 2, 123, 54 } and {1, 0, 2} I get true and not false. I belive the problem is in the check method but I can't locate the problem.
Check this code I wrote right now, I added comments to the code, and if you run it. I wrote some text on the console to explain to you how it's working. So at the end when you want to use it, just remove the system.out.print
public class ArrayPattern {
static int numbers[] = {1,10,20,3,30};
static int pattern[] = {0,0,2,2};
public static void main(String[] args) {
System.out.println(isPattern(0, 0));
}
/**
* Recursive method that checks for the pattern. If it fails to match pattern starting from index i, it
* tries starting from index i+1
* */
public static boolean isPattern(int index, int consec){
// If all pattern values where matched consecutively
if(consec == pattern.length)
return true;
// If the numbers ended and the pattern wasn't found
if(index == numbers.length)
return false;
// If the current number matches the pattern, check the next number at index + 1
if(checkPattern(pattern[consec], numbers[index])){
System.out.println(pattern[consec] +" => "+ numbers[index]);
return isPattern(index+1, consec+1);
}
// If the pattern was not found, starting from a specific index. Start from the next index to check if the pattern can be found
System.out.println(String.format("\nFailed to match pattern, try starting from index: %d\n", (index - consec + 1)));
return isPattern(index - consec + 1, 0);
}
/**
* Just chesk the pattern:
* 0 => 1 or 2 digits.
* 1 => 1 digit.
* 2 => 2 digits
*/
public static boolean checkPattern(int pattern, int value){
String sValue = String.format("%d", value);
switch (pattern) {
case 0:
return sValue.length() <= 2;
default:
return sValue.length() == pattern;
}
}
}
A truly recursive solution might be the following:
import java.util.Arrays;
public class Checker {
//0 represent one or two digits number,
//1 represent one digit numbers and
//2 represent two digits numbers
public boolean match(int [] a, int [] pattern, int i, int j)
{
if(pattern.length == 0) return true;
if(pattern.length == a.length) {
return check(a, pattern);
} else {
return false;
}
}
//recursive function
private boolean check(int [] a, int [] pattern) {
boolean firstDigitCheck = false;
switch (pattern[0]) {
case 0: firstDigitCheck = checkDigits(a[0]) <3;break; // 1 or 2
case 1: firstDigitCheck = checkDigits(a[0]) <2;break; // 1
case 2: firstDigitCheck = checkDigits(a[0]) ==2;break// 2
default:break;//not important (we trust the pattern format)
}
if (a.length==1) {//base step (array of dimension 1)
return firstDigitCheck;
} else {//recursive step on the left-truncated arrays
return firstDigitCheck && check(Arrays.copyOfRange(a, 1, a.length), Arrays.copyOfRange(pattern, 1, pattern.length));
}
}
public int checkDigits(int k){
int length = (int)(Math.log10(k)+1);
return length;
}
}
If I understand your question, then the element in array, "a", at index 'j' can have a certain number of digits based on the number at the element at index 'j' in pattern.
You could accomplish this with a for loop;
boolean result = true;
int [...] a = ...
int [...] pattern = ...
for (int j = 0; j < a.length(); j++) {
if (result) {
if (pattern[j] = 0) {
if (a[j].toString().length() > 2) {
result = false;
}
} else if (pattern[j] = 1) {
if (a[j].toString().length() != 1) {
result = false;
}
} else if (pattern[j] = 2) {
if (a[j].toString().length() != 2) {
result = false;
}
}
}
}
That should get the job done, or something similar.
I am a little unclear with your code. But it can be done in a simpler way using a for loop.
The basic algorithm you need to follow would be:
j=0
for(i = 0 to a.length){
if number of digits(a[i]) == pattern[j] {
j++
}
}
if j == pattern.length
print its a match
else
it is not.
This small piece of code will work for every case.
Instead of the for loop, just call it every time.

Categories

Resources