Java - Values aren't reflecting after recursion call - java

I ran into an issue while getting value for a List<List<Integer>> called res. It's a recursive call and that call is supposed to fill this "res", however when the recursive function is called by another function and that function is returning an empty list. But when I do log it, I can see the values. Here's the code:
class Solution {
public List<List<Integer>> combinationSum(int[] arr, int k) {
// given an arr and a sum k, find all the subsequences that sum upto k
// we can use backtracking here as we need all the options
// there are 2 choices for every element:
// either we can take it in the subres or discard it
// if we take it once, we can take it n times till the target is reached
Arrays.sort(arr);
List<List<Integer>> res = new ArrayList<>();
List<Integer> subRes = new ArrayList<>();
combinationSum(0, arr, k, 0, res, subRes);
return res;
}
public void combinationSum(int i, int[] arr, int k, int sum,
List<List<Integer>> res,
List<Integer> subRes){
if(sum == k) {
if(!res.contains(subRes)) res.add(subRes);
System.out.println("res = " + res);
return;
}
if(i == arr.length || sum > k) return;
subRes.add(arr[i]);
sum += arr[i];
combinationSum(i, arr, k, sum, res, subRes);
subRes.remove(new Integer(arr[i]));
sum -= arr[i];
combinationSum(i + 1, arr, k, sum, res, subRes);
}
}
I'm stuck badly on this,
Thanks in advance.

The mutations you make to subRes in the recursion is affecting what you see in res. Before adding subRes into res, make a new copy of it.
if(!res.contains(subRes)) {
res.add(new ArrayList<>(subRes));
}
In your code, correct list (subRes) is added to res, but you mutate/modify subRes by removing elements sometime later when the recursive call returns.

Related

What would be an efficient way to check duplicate answer in the following case?

I am trying to solve this problem in leetcode: https://leetcode.com/problems/combination-sum/
public List<List<Integer>> combinationSum(int[] candidates, int target)
{
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(candidates);
helper(candidates, target, res, new ArrayList<>(), 0);
return res;
}
private void helper (int[] candidates, int target, List<List<Integer>> res, List<Integer> temp, int index) {
if( target < 0) return;
if(target == 0) {
res.add(new ArrayList<>(temp));
return;
}
for(int i = index; i < candidates.length; i++) {
if(candidates[i] > target) {
return;
}
temp.add(candidates[i]);
helper(candidates, target - candidates[i], res, temp, index);
temp.remove(temp.size() - 1);
}
}
For an input: candidates = [2,3,6,7], and target = 7
My output is: [[2,2,3],[2,3,2],[3,2,2],[7]]
Correct Output: [[2,2,3],[7]]
Obviously, I need to check for a duplicate before adding to the result.
I understand I can create a set of strings where each string will be a sorted version of the list e.g., [2,3,2] => "223". This will help me to check whether I need to add the list to the result or not.
My question is what would be the best way to check for a duplicate in my situation?
By adding the following lines in your helper method would do the expected result.
if(target == 0 ) {
Collections.sort(temp); // This will sort your list, that you want to add
if(!res.contains(temp)) // Check if sorted list already existing in your result list or not. Only add the temp list if it does not exist in your res list.
res.add(new ArrayList<>(temp));
return;
}
or else you can also add the elements in sorted order in your res list and then use HashSet to remove the duplicates from your res list.
Set<List<Integer>> set = new HashSet<>(res);
res.clear();
res.addAll(set);
One possible alternative approach to avoid duplicates entirely (without having to explicitly check for them) would be as follows:
Instead of looping through every element in the for loop in your helper function (note that the index parameter is always same in your recursive calls), you can think of the solution as follows:
Either you consider the element at given index, and recurse again with the same index(thus being able to consider the same element multiple times) OR
You don't consider the current element, and recurse with index+1.
This way you wouldn't end up getting duplicates in your solution.
Not posting the entire solution here (don't want to rob you of all the fun :P ), but the recursive steps in the helper function would essentially be:
# don't consider element at index, and increment index in recursive call
self.helper(candidates, target, index+1, res, temp)
# consider element at index `index`
self.helper(candidates, target-candidates[index], index, res, temp+[candidates[index]])
I'm not sure what best means, but you can use Collection.sort and Set
public static Set<List<Integer>> combinationSum(int[] candidates, int target)
{
--->> Set<List<Integer>> res = new HashSet<>();
Arrays.sort(candidates);
helper(candidates, target, res, new ArrayList<>(), 0);
return res;
}
private static void helper(int[] candidates, int target, Set<List<Integer>> res, List<Integer> temp, int index) {
if( target < 0) return;
if(target == 0) {
ArrayList<Integer> newRes = new ArrayList<>(temp);
--->> Collections.sort(newRes);
res.add(newRes);
return;
}
for(int i = index; i < candidates.length; i++) {
if(candidates[i] > target) {
return;
}
temp.add(candidates[i]);
helper(candidates, target - candidates[i], res, temp, index);
temp.remove(temp.size() - 1);
}
}
Input
candidates = [2,3,6,7], and target = 7
Output
[[2, 2, 3], [7]]
You don't necessarily need a Set for this. You could instead just sort both your Arrays using Arrays.sort() an then check for equality over all indexes, e.g. like this:
public Boolean isEqual(int[] a1, int[] a2) {
if (a1.length != a2.length) {
return false;
}
Arrays.sort(a1);
Arrays.sort(a2);
for (int i = 0; i < a1.length; i++) {
if (a1[i] != a2[i]) {
return false;
}
}
return true;
}
Apply this for your result and keep the Arrays results that return false.

Recursive Selection sort Java

I've been looking for a recursive selection sort, using only 2 parameters:
The array that has to be sorted
a value k, which indicates till which
element it has to be sorted.
Example: SelectionSort(array[] a, int k) with a being {6,3,5,7,2} and k being 2 will sort the first 3 elements, and will keep the last elements untouched.
I was thinking about starting with an if-statement for k being 0, and if that was the case, it would just return the array as it is, since you cant sort an array of size 1.
Something like:
public int[] sort(int[] a){
a = selectionSort(a, n-1);
return a;
}
public int[] selectionSort(int[] a, int k){
if (k = 0){
return a;
}
else{
selectionSort(a, k-1 );
... (part i really don't know)
}
I have no clue how to do the 'else' part since I only know that it has to call the method again.
I'm not allowed to create other methods. I also need to make sure I use exactly 2 parameters, nothing more, nothing less.
I have to work it out in pseudocode, but I understand some Java, so if someone could help me by using either pseudo, or Java, it would be so helpful
First some remarks to your code:
Your methods sort and selectionSort don't need to return an int[] array,
since the array object a stays the same all the time.
It is only the content within this array which changes.
Hence, you can use void as return-type.
In your if use (k == 0) instead of (k = 0)
You already figured out the first part.
Here it is how you can do the second part in pseudo code:
public void selectionSort(int[] a, int k) {
if (k == 0) {
return;
}
else {
selectionSort(a, k-1 );
find x such that a[x] is the smallest of a[k] ... a[a.length - 1]
if (a[k-1] > a[x]) {
swap a[k-1] and a[x]
}
}
}
I'm sure you are able to refine the pseudo code to real Java code.
By doing a simple google search, I found the biggest part of the code below on this site. I added the selectionSort method myself to suit your parameters.
public void selectionSort(int a[], int n)
{
recurSelectionSort(a, n, 0);
}
// Recursive selection sort. n is size of a[] and index
// is index of starting element.
static void recurSelectionSort(int a[], int n, int index)
{
// Return when starting and size are same
if (index == n)
return;
// calling minimum index function for minimum index
int k = minIndex(a, index, n-1);
// Swapping when index nd minimum index are not same
if (k != index){
// swap
int temp = a[k];
a[k] = a[index];
a[index] = temp;
}
// Recursively calling selection sort function
recurSelectionSort(a, n, index + 1);
}
// Return minimum index
static int minIndex(int a[], int i, int j)
{
if (i == j)
return i;
// Find minimum of remaining elements
int k = minIndex(a, i + 1, j);
// Return minimum of current and remaining.
return (a[i] < a[k])? i : k;
}

Getting all combinations from a list using recusion, including combinations that use the same number

I have a list of numbers: [10, 13, 15]. I am trying to find the combinations of numbers in the list that add up to or are less than the target of 28.
Currently I have a recursive method:
public void combinations(ArrayList<Integer>data,int fromIndex, int endIndex)
{
int sum = 0;
int target = 28;
ArrayList<Integer>results = new ArrayList<Integer>();
if(fromIndex == endIndex)
{
return;
}
for(int currentIndex = fromIndex; currentIndex < endIndex; currentIndex++)
{
if(sum + data.get(currentIndex) <= target)
{
results.add(data.get(currentIndex));
sum +=data.get(currentIndex);
}
}
System.out.println(results);
combinations(data, fromIndex + 1, endIndex);
}
Currently this outputs:
[10, 13],[13, 15],[15] which are correct and I understand why I am getting these solutions as my recursive method has a +1. However other solutions such as [10],[13],[10,10] ect are not included and I was wondering how I would go about implementing this, would I need to change my increments in my recursive method?
public static void combinations(ArrayList<Integer> arr, ArrayList<ArrayList<Integer>> ans, int startIndex, int endIndex, int sum) {
if(startIndex > endIndex) {
for(ArrayList<Integer> x : ans) {
System.out.println(x);
}
return;
}
ArrayList<Integer> newTemp;
ArrayList<ArrayList<Integer>> newAns = new ArrayList<ArrayList<Integer>>();
for(ArrayList<Integer> x : ans) {
newAns.add(x);
}
for(ArrayList<Integer> x : ans) {
int s = 0;
newTemp = new ArrayList<Integer>();
for(Integer v : x) {
newTemp.add(v);
s+=v;
}
if(s + arr.get(startIndex) <= sum) {
newTemp.add(arr.get(startIndex));
newAns.add(newTemp);
}
}
if(arr.get(startIndex) <= sum ) {
newTemp = new ArrayList<Integer>();
newTemp.add(arr.get(startIndex));
newAns.add(newTemp);
}
combinations(arr,newAns, startIndex+1, endIndex, sum);
}
I have to rewrite your code as I was unable to think through your code.
Secondly, I have to make a newArrayList all time to avoid ConcurrentModificationException which I have faced the first time and will overcome later after gaining some knowledge about it.
Now, this method should be called as
public static void main (String[] args) {
ArrayList<Integer> arr = new ArrayList<Integer>();
arr.add(10);
arr.add(15);
arr.add(13);
arr.add(-5);
arr.add(28);
combinations(arr, new ArrayList<ArrayList<Integer>>(), 0, 4, 28);
}
Explanation: I have generalized your question's answer to fit any sum in int range.
I have made ArrayList of ArrayList which will print all the combinations at the base case.
I have first added an ArrayList containing single element i.e current element if the current element is the <= sum.
Then with all remaining ArrayList, I have calculated the sum of each and then check whether adding the current element into the previous ArrayList holds the above condition.
At the same time I have made new ArrayList and copied all elements while I was calculating the sum of each ArrayList and then if the second case holds good then I added the current element into temp ArrayList and then added the temp ArrayList to the answer ArrayList of ArrayLists.
Then I called the recursion by incrementing the startIndex by 1.

Recursive function to difference between two values in array

I'm using Java.
I need to implement a recursive function that calculates the difference between each two values and returns for me array in size 2 [MAXIMUM_DIFF, STARTINDEX].
For the following array:
arr = {1, 4, 60, -10, 2, 7, 56, -10}
The recursive method returns array in size 2: [70,2] because the maximum difference is 70 (60-(-10)=70) and the index of 60 is 2.
I have 90% from the solution:
public static int[] getMax(int[] arr) {
int [] retArr = new int[2];
if(arr.length == 1)
return retArr;
else {
return getMax(arr, retArr);
}
}
public static int[] getMax(int[] arr, int[] retArr) {
if(retArr[1] == arr.length - 1)
return retArr;
int currentMaxVal = arr[retArr[1]] - arr[retArr[1] + 1];
if(currentMaxVal > retArr[0]) {
retArr[0] = currentMaxVal;
}
retArr[1] = retArr[1] + 1;
return getMax(arr, retArr);
}
But the result is[70,7] instead of [70,2] because this line retArr[1] = retArr[1] + 1;
This is because I don't know where to save the index, So how can I save the index?
*I'm not sure about the second param of getMax(int [] arr, int []retArr)
Its can be different maybe
I cant add another parameters, Maybe to change the second param of getMax(int [] arr, int []retArr), And I can't use static variables
if(currentMaxVal > retArr[0])
{
retArr[0] = currentMaxVal;
}
retArr[1] = retArr[1] + 1;
Should be
if(currentMaxVal > retArr[0])
{
retArr[0] = currentMaxVal;
retArr[1] = currentIndex;
}
And currentIndex should be an additional parameter passed to the function. (and other references to current index updated accordingly)
UPDATE:
I think the point here is to understand "divide and conquer", where you break up the problem into a smaller problem, and then sort through for the best one. Something like this (if a bit more awkward then a normal case)
public static int[] getMax(int[] arr, int[] retArr) {
// Return case
if (retArr[1] >= arr.length - 1)
return new int[] { Integer.MIN_VALUE, retArr[1] };
// Save context
int index = retArr[1];
int value = arr[index] - arr[index + 1];
// Call recursion
retArr[1]++;
int[] temp = getMax(arr, retArr);
// Return best between current case and recursive case
if (temp[0] > value)
return temp;
else
return new int[] { value, index };
}
Each call (or stack) of the recursive function is its own context. That means variables declared in it won't be overwritten in the recursive calls. The idea is that you break a hard problem down recursively until you can't break it down any further. Then you solve it by putting together the results of each call one at a time until you have your final answer. (This works better with less trivial cases like the fibonacci sequence) Also note that anything that can be done in a loop will always be more efficient then recursion.

Java ArrayList initialization

I've been trying to understand the following code that uses Depth-First-Search (DFS) to print out all unique combinations of length k comprising of numbers [1..n]
Please see the line commented "doubt" in the private dfs function
public ArrayList<ArrayList<Integer>> combine(int n, int k) {
ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
if (n <= 0 || n < k)
return result;
ArrayList<Integer> item = new ArrayList<Integer>();
dfs(n, k, 1, item, result);
return result;
}
private void dfs(int n, int k, int start, ArrayList<Integer> item,
ArrayList<ArrayList<Integer>> res) {
if (item.size() == k) {
res.add(new ArrayList<Integer>(item)); /*doubt*/
return;
}
for (int i = start; i <= n; i++) {
item.add(i);
dfs(n, k, i + 1, item, res);
item.remove(item.size() - 1);
}
}
If I change it to res.add(item) it returns result as list of null lists. ListObject.add(E e) is a perfectly valid function, why doesn't it work here?
So your question concerns these two alternatives:
// works
res.add(new ArrayList<Integer>(item));
// won't work, results in empty lists
res.add(item);
The purpose of new ArrayList<Integer>(item) is to create a new list with the same content as the original, effectively cloning the original.
If you don't clone the original, it will stay empty. The first time dfs is called, item is empty, and then look at this loop:
for (int i = start; i <= n; i++) {
item.add(i);
dfs(n, k, i + 1, item, res);
item.remove(item.size() - 1);
}
Every element added to item will be later removed. This is why you end up with empty lists without the cloning step. Without cloning, not only you get a list of empty lists, all of the empty lists are actually the same original ArrayList that you created in combine, before the first call to dfs.
It's because item.remove(item.size() - 1); is modifying the same list that you just added to your list of results. So it always ends up removing all the items. The solution you have is actually copying the list of items and storing them in your result list. No one has a reference to that list so it doesn't get modified.

Categories