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);
}
Related
I'm learning Java, and I'm stuck on a recursion problem.
I need to use a recursive method to check if a number is an Armstrong number or not.
My code:
public class ArmstrongChecker {
public boolean isArmstrong(int number) {
// check if the number is a negative number
if (number < 0) {
return false;
}
ArmstrongChecker armstrongChecker = new ArmstrongChecker();
// find the length of the number
int length = armstrongChecker.lengthChecker(number);
// create a variable to store the sum of the digits of the number
int sum = 0;
// find the individual digits and raise to the power of the numbers of digits
if (number != 0) {
int digit = Math.floorMod(number, 10);
int powerRaised = (int) Math.pow(digit, length);
sum = sum + powerRaised;
isArmstrong(number / 10);
}
return sum == number;
}
// method to check the length of the number
public int lengthChecker(int number) {
int length = String.valueOf(number).length();
return length;
}
}
How do I prevent int length in isArmstrong() method from changing its value.
While you are not changing it's value in the posted code, you could mark that variable to be a constant. This way the compiler can error out if you tried to assign a new value.
final int length = armstrongChecker.lengthChecker(number);
As I've already said in the comments, your solution has the following issues:
The result of the recursive call isArmstrong() is being ignored;
There's no need for spawning new instances of ArmstrongChecker. And this method doesn't require object creation at all, it can be implemented as static.
Checking if the number is an Armstrong number boils down to calculating its Armstrong sum, the solution will be cleaner if you implement only this part using recursion.
It might look like this:
public static boolean isArmstrong(int number) {
if (number < 0) return false;
if (number < 10) return true;
return number == getArmstrongSum(number, String.valueOf(number).length());
}
public static int getArmstrongSum(int number, int power) {
if (number == 0) {
return 0;
}
return (int) Math.pow(number % 10, power) + getArmstrongSum(number / 10, power);
}
main()
public static void main(String[] args) {
System.out.println(isArmstrong(370)); // true
System.out.println(isArmstrong(12)); // false
System.out.println(isArmstrong(54)); // false
System.out.println(isArmstrong(153)); // true
}
Output:
true
false
false
true
You need to get the length once for whole recursion, so the cleanest approach would be to pass down both the number and the length into the recursion. An easy way to do this is to have one method that is the public face of the API, and another that does the recursion.
public class ArmstrongChecker {
public boolean isArmstrong(int number) {
if (number < 0) {
return false;
}
int length = lengthChecker(number);
int sum = armstrongSum(number, length);
return sum == number;
}
private int armstrongSum(int number, int length) {
int sum = 0;
if (number != 0) {
int digit = Math.floorMod(number, 10);
int powerRaised = (int) Math.pow(digit, length);
sum += powerRaised;
sum += armstrongSum(number / 10, length);
}
return sum;
}
public int lengthChecker(int number) {
int length = String.valueOf(number).length();
return length;
}
}
This is pretty common in recursion, where the parameters to the recursive part of the algorithm are a little different (usually there are more of them) than what you want a client of the API to have to pass in. The number changes in each recursive call, where number / 10 is passed down, but the same length is passed all the way through.
Notice that the recursive armstrongSum uses the return value from the recursive call, and that there is no need to create another instance of ArmstrongChecker when you are already in an instance method of the class.
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;
}
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));
}
}
Having trouble with this problem on an assignment I'm working on. I believe the problem is that the method will never return a negative value, but I'm not sure why that is or how to fix it. (Also, this has to be done using recursion, even though that is probably the worst way to accomplish it.
private static int findMaxOfLessThanFirst(int[] numList, int startIndex, int endIndex, int firstNum) {
if(startIndex>-1&&startIndex<100){
if(startIndex==endIndex){
if(numList[startIndex]<=firstNum){
return numList[startIndex];
} else {
return 222; //number used for testing
}
}
if(numList[startIndex]>=
findMaxOfLessThanFirst(numList,startIndex+1,endIndex,firstNum) &&
numList[startIndex]<=firstNum){
return numList[startIndex];
} else {
return findMaxOfLessThanFirst(numList,startIndex+1,endIndex,firstNum);
}
} return 333; //number used for testing
}
The goal is to return the integer in the array that is largest while ignoring all of the numbers that are larger than numList[0].
private static int findMaxOfLessThanFirst(int[] numList, int currentIndex, int len, int currentMax) {
// when you reach the end of the array, return the currentMax
if (currentIndex == len - 1) {
return currentMax;
}
int firstElement = numList[0];
// if the current element we are looking at in this stage of the recursion is greater
// than the first element, ignore it and recurse on the next element
if (numList[currentIndex] >= firstElement) {
return findMaxOfLessThanFirst(numList, currentIndex + 1, len, currentMax);
}
int newMax;
// if none of the previous conditions were true, and this current value is greater than
// the currentMax, update the currentMax
if (numList[currentIndex] > currentMax) {
newMax = numList[currentIndex];
}
return findMaxOfLessThanFirst(numList, currentIndex + 1, len, newMax);
}
When you call this function, set your currentMax to something like the minimum integer value. This way you can check the return value at the end to see if you did, in fact, have an element less than the first element.
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.