Java Recursion on an ArrayList - java

I have an ArrayList of int.
The main program - calls a method to get a list of the sum of all (n member) combination of the members of the list. Where n can be anywhere between 2 - 6. E.g. Original List is {1,2,3,4,5}; Then the output should be {6, 7, 8, 8, 9, 10, 9, 10, 11, 12} where n = 3;
I am looking for the optimum way to do this. Right now, the way I have written the program (which is working) is without recursion. I have methods for all numbers i.e.
MyMethod2 -- gives me all the sum of 2 member combinations of MyArrayList
MyMethod3 -- gives me all the sum of 3 member combinations of MyArrayList
MyMethod4 -- gives me all the sum of 4 member combinations of MyArrayList
......
So, you can see that there is a lot of duplicate set of codes.
Also the way the program has currently been written (e.g. My Method3):
MyMethod3
ArrayList<Integer> sum = new ArrayList<Integer>();
for (i = 0; i < MyArrayList.size(); i++){
for (j = i + 1; j < MyArrayList.size(); j++){
for (k = j + 1; k < MyArrayList.size(); k++){
int total = MyArrayList.get(i) + MyArrayList.get(j) + MyArrayList.get(k);
sum.add(total);
}
}
}
return sum;
The MyMethod for n = 6, can become pretty long. Also "n" can change in the future.
Is there a better way to do this using recursion to minimize duplicate code, and using the number n as a variablefor the method call. Is there a standard package in Java that can help with recursion.
Adding the Code based on #Maertin suggestion - which worked for me
ArrayList<Integer> myArray = new ArrayList<Integer>();
myArray.add(5);
myArray.add(6);
myArray.add(4);
myArray.add(2);
myArray.add(1);
ArrayList<Integer> finalSumArray = combineTwoArrayList(3, myArray, myArray);
public static ArrayList<Integer> combineTwoArrayList(int n, ArrayList<Integer> origArray, ArrayList<Integer> finalSumArray) {
if (n == 1) return finalSumArray;
ArrayList<Integer> finalSumArray = new ArrayList<Integer>();
for (int i = 0; i < sumArray.size() - 1; i++){
for (int j = i + 1; j < origArray.size(); j++){
finalSumArray.add(sumArray.get(i) + origArray.get(j));
}
}
--n;
return combineTwoArrayList(n, origArray, finalSumArray);
}

You are correct in wanting to do this via recursion, because now, instead of having three separate methods, you could have one method with a parameter n for n-member combinations.
public int nCombinationSum( int n, int i, ArrayList<Integer> arr, ArrayList<Integer> sumArr) {
/* Gets n-combination sums and puts into sumArr
Input: n consecutive element combination, current index i in arr, and output ArrayList
Output: Gets n consecutive element combinations in arr from index i to index (i + n) and puts into sumArr
*/
//**BASE CASE**
//if index out of arr bounds
if( i + n > arr.size() )
return 0;
//**RECURSIVE CASE**
else {
//sum of values in arr from i to (i + n)
int currComboSum = 0;
for( int j = 0; j < n; j++ )
currComboSum += arr.get(j);
//adding sum to next element in resultant array
sumArr.add( currComboSum );
return nCombinationSum( n, i + 1, arr, sumArr );
}
}
USAGE
In your main method, you can call nCombinationSum and provide it with the kind of combination (n), starting index (in your case, 0), and arrayList (arr), and the arrayList you want to append the sums in (sumArr).
This also has the potential added benefit of allowing you to add any n-combination sum starting from a certain index. If you would like, you could add an end index as well, but this is fairly extended as it is.
EDIT: Please edit your question to reflect that you want the result to be an arrayList of sums, rather than the total sum. It is not clear right now.
Basically, what you want to do with recursion, in general, is to set a base case and a recursive case.
Your base case would be if your index is out of bounds, because you're going to call all elements from index i to i + n.
For the recursive case, use the algorithm below to account for each element in arr, then just keep returning the function with the next index value, and the function will continue running until it is out of bounds.
Algorithm
Getting sum of n-combination elements
Appending that sum into resultant array sumArr
Feel free to refer to the code above for reference.

You can use recursion. Basically, you should have only two for loops. (which is the code for two member combinations). When you compute 'total', pass each 'total' value to an ArrayList MyArrayList2. Now for MyMethod3, you use the elements of MyArrayList2 and the original ArrayList and find new 'total' values again and pass that to MyArrayList3. For MyMethod4, you use the elements of MyArrayList3 and the original ArrayList and find new 'total' values again and pass that to MyArrayList4.... ....

Related

How to implement compareTo in a generic method that takes a generic array as argument?

I'm trying to implement a method, that, given a generic array, and two index values, slice the array, and find the largest element between the two given numbers.
<T extends Comparable<? super T>> T max(T[] array, int firstIndx, int secondIndx) { //requires comparable
T maxElement = array[0]; //8
System.out.println(Arrays.toString(array));
for (int i = firstIndx; i < secondIndx - 1; i++) {
for (int j = firstIndx + 1; j < secondIndx; j++) {
if (array[i].compareTo(array[j]) > 0) {
maxElement = array[i];
array[i] = array[j];
array[j] = maxElement;
}
}
}
System.out.println(Arrays.toString(array));
return maxElement;
}
But for an arrays of ints [8, 4, 6, 20, 1], is swapping correctly just the first two elements, giving me the wrong maximum elements. What's wrong with the code ?
There are two issues with your sort. The first is that you're using firstIndx and secondIndx, but based on how your code is structured, it's treating that second number as if it were the second index minus 1.
The second issue is that your inner loop is starting back at firstIndx every time, which breaks the bubble sort. It needs to start at i.
Try this modification to your for loops:
for (int i = firstIndx; i <= secondIndx - 1; i++) { // Notice the "<=".
for (int j = i + 1; j <= secondIndx; j++) { // j starts at i
// ... existing bubble sort code goes here
}
}
Edit: I failed to mention that your approach won't find the max if the max is already in its sorted position. You should just grab the max from array[secondIndx] after you're done sorting.
As an aside, firstIndx is a pretty bad variable name. It's only one letter more to write it out in full: firstIndex.

Dynamic programming with Combination sum inner loop and outer loop interchangeable?

I am a little confuse about the dynamic programming solution for combination sum, that you are given a list of numbers and a target total, and you want to count how many ways you can sum up to this target sum. Numbers can be reused multiple times. I am confused about the inner loop and outer loop that whether they are interchangeable or not. Can some explain the difference between the following two, and in what case we would use one but not the other, or they are the same.
int [] counts = new int[total];
counts[0] = 1;
// (1)
for(int i = 0; i <= total; i++) {
for(int j = 0; j < nums.length; j++) {
if(i >= nums[j])
counts[i] += counts[i - nums[j]];
}
}
// (2)
for(int j = 0; j < nums.length; j++)
for(int i = nums[j]; i <= total; i++) {
counts[i] += counts[i - nums[j]];
}
}
The two versions are indeed different, yielding different results.
I'll use nums = {2, 3} for all examples below.
Version 1 finds the number of combinations with ordering of elements from nums whose sum is total. It does so by iterating through all "subtotals" and counting how many combinations have the right sum, but it doesn't keep track of the elements. For example, the count for 5 will be 2. This is the result of using the first element (with value 2) and finding 1 combination in nums[3] and another combination for the second element (value 3) with the 1 combination in nums[2]. You should pay attention that both combinations use a single 2 and a single 3, but they represent the 2 different ordered lists [2, 3] & [3, 2].
Version 2 on the other hand find the number of combinations without ordering of elements from nums whose sum is total. It does so by counting how many combinations have the right sum (fur each subtotal), but contrary to version 1, it "uses" each element completely before moving on to the next element thus avoiding different orderings of the same group. When counting subtotals with the first element (2), all counts will initially be 0 (except the 0 sum sentinel), and any even subtotal will get the new count of 1. When the next element used, it is as if it's coming after all 2's are already in the group, so, contrary to version 1, only [2, 3] is counted, and not [3, 2].
By the way, the order of elements in nums doesn't affect the results, as can be understood by the logic explained.
Dynamic programming works by filling out entries in a table assuming that previous entries in the table have been fully completed.
In this case, we have counts[i] is dependent on counts[i - nums[j]]; for every entry j in nums.
In this code snippet
// (1)
for(int i = 0; i < total; i++) {
for(int j = 0; j < nums.length; j++) {
if(i >= nums[j])
counts1[i] += counts1[i - nums[j]];
}
}
We fill the table in order from 0 to total in that order. This is the action of the outer loop. The inner loop goes through our different nums and updates the current entry in our table based on the previous values, which are all assumed to be completed.
Now look at this snippet
// (2)
for(int j = 0; j < nums.length; j++){
for(int i = nums[j]; i < total; i++) {
counts2[i] += counts2[i - nums[j]];
}
}
Here we are iterating through our list of different counts and updating our totals. This breaks the concept of dynamic programming. None of our entries can ever be assumed to be complete until we are completely finished with our table.
Are they the same? The answer is no they are not. The following code illustrates the fact:
public class dyn {
public static void main(String[] args) {
int total = 50;
int[] nums = new int[]{1, 5, 10};
int [] counts1 = new int[total];
int [] counts2 = new int[total];
counts1[0] = 1;
counts2[0] = 1;
// (1)
for(int i = 0; i < total; i++) {
for(int j = 0; j < nums.length; j++) {
if(i >= nums[j])
counts1[i] += counts1[i - nums[j]];
}
}
// (2)
for(int j = 0; j < nums.length; j++){
for(int i = nums[j]; i < total; i++) {
counts2[i] += counts2[i - nums[j]];
}
}
for(int k = 0; k < total; k++){
System.out.print(counts1[k] + ",");
}
System.out.println("");
for(int k = 0; k < total; k++){
System.out.print(counts2[k] + ",");
}
}
}
This will output 2 different lists.
They are different because we are updating our counts[i] with incomplete information from earlier in the table. counts[6] assumes you have the entry for counts[5] and counts[1], which in turn assume you have the entries for counts[4], counts[3], counts[2], and counts[0]. Thus, each entry is dependent on (in the worst case all of) the previous entries in the table.
Addendum:
Interesting (perhaps obvious) side-note:
The two methods produce the same list up until the smallest pairwise sum of entries in nums.
Why?
This is when the information from previous entries becomes incomplete (with respect to the first loop). That is, if we have int[] nums = new int[]{3, 6}, then counts[3+6] will not be computed correctly, because either
count[3] will not be right or count[6] will not align with the result obtained using the first loop, depending on which stage of the computation we have done yet.
In light of criticism of my previous answer, I thought I'd take a more mathematical approach.
As in #Amit 's answer, I will use nums = {2, 3} in examples.
Recurrence Relations
The first loop computes
S(n) = S(n-3) + S(n-2)
Or, more generally, for some set {x_1, x_2, x_3, ... ,x_k}:
S(n) = S(n- x_1) + S(n- x_2) + ... + S(n- x_k)
It should be clear that each S(n) is dependent on (possibly all) previous values, and so we must start on 0 and populate the table upwards to our desired total.
The second loop computes a recurrence S_2(n) with the following definitions:
S_1(n) = S_1(n-2)
S_2(n) = S_1(n) + S_2(n-3)
More generally, for some set {x_1, x_2, x_3, ... ,x_k}:
S_1(n) = S_1(n- x_1)
S_2(n) = S_1(n) + S_2(n- x_2)
...
S_k(n) = S_{k-1}(n) + S_k(n- x_k)
Each entry in this sequence is like those from the first loop; it is dependent on the previous entries. But unlike the first loop, it is also dependent on earlier sequences.
Put perhaps more concretely:
S_2 is dependent on not only (possibly all) previous entries of S_2, but also on previous entries of S_1.
Thus, when we want to compute the first recurrence, we begin at 0 and compute each entry, for each number in our nums.
When we want to compute the second recurrence, we compute each intermediate recurrence one at a time, each time storing the result in counts.
In Plain English
What do these two recurrences compute? As #Amit 's answer explains, they compute the number of combinations that sum to total, with and without preserving order. It's easy to see why, again using our example of nums = {2, 3}:
Note my use of the word list to denote something ordered, and the word set to denote something unordered.
I use append to mean adding to the former, and add to denote adding to the latter.
If you know
how many lists of numbers add to 2,
and how many add to 3,
and I ask you
how many add to 5?
You can append a 3 to every one of the former lists, and a 2 to every one of the latter lists.
Thus (how many add to 5) = (how many add to 3) + (how many add to 2)
Which is our first recurrence.
For the second recurrence,
If you know
how many sets of just 2's add to 5 (0)
how many sets of just 2's and 3's add to 2 (1)
You can just take all of the first number, and you can add a 3 to all the sets in the second number.
Note how "sets of just 2's" is a special case of "sets of just 2's and 3's". "sets of just 2's and 3's" depends on "sets of just 2's", just like in our recurrence!
Recursive functions written in java
The following recursive function computes the values for the first loop, with example values 3 and 2.
public static int r(int n){
if(n < 0)
return 0;
if(n == 0)
return 1;
return r(n-2) + r(n-3);
}
The following set of recursive functions computes the values for the second loop, with example values 3 and 2.
public static int r1(int n){
if(n < 0)
return 0;
if(n == 0)
return 1;
return r1(n-2);
}
public static int r2(int n){
if(n < 0){
return 0;
}
return r1(n) + r2(n-3);
}
I have checked them up to 10 and they appear to be correct.

How to know the fewest numbers we should add to get a full array

recently I met a question like this:
Assume you have an int N, and you also have an int[] and each element in this array can only be used once time. And we need to design an algorithm to get 1 to N by adding those numbers and finally return the least numbers we need to add.
For example:
N = 6, array is [1,3]
1 : we already have.
2 : we need to add it to the array.
3 : we can get it by doing 1 + 2.
4: 1 + 3.
5 : 2 + 3.
6 : 1 + 2 + 3.
So we just need to add 2 to our array and finally we return 1.
I am thinking of solving this by using DFS.
Do you have some better solutions? Thanks!
Here's an explanation for why the solution the OP posted works (the algorithm, briefly, is to traverse the sorted existing elements, keep an accumulating sum of the preceding existing elements and add an element to the array and sum if it does not exist and exceeds the current sum):
The loop tests in order each element that must be formed and sums the preceding elements. It alerts us if there is an element needed that's greater than the current sum. If you think about it, it's really simple! How could we make the element when we've already used all the preceding elements, which is what the sum represents!
In contrast, how do we know that all the intermediate elements will be able to be formed when the sum is larger than the current element? For example, consider n = 7, a = {}:
The function adds {1,2,4...}
So we are up to 4 and we know 1,2,3,4 are covered,
each can be formed from equal or lower numbers in the array.
At any point, m, in the traversal, we know for sure that
X0 + X1 ... + Xm make the largest number we can make, call it Y.
But we also know that we can make 1,2,3...Xm
Therefore, we can make Y-1, Y-2, Y-3...Y-Xm
(In this example: Xm = 4; Y = 1+2+4 = 7; Y-1 = 6; Y-2 = 5)
Q.E.D.
I don't know if this is a good solution or not:
I would create a second array (boolean array) remembering all numbers I can calculate.
Then I would write a method simulating the adding of a number to the array. (In your example the 1, 3 and 2 are added to the array).
The boolean array will be updated to always remember which values (numbers) can be calculated with the added numbers.
After calling the add method on the initial array values, you test for every Number x ( 1 <= x <= N ) if x can be calculated. If not call the add method for x.
since my explanation is no good I will add (untested) Java code:
static int[] arr = {3,5};
static int N = 20;
//An Array remembering which values can be calculated so far
static boolean[] canCalculate = new boolean[N];
//Calculate how many numbers must be added to the array ( Runtime O(N^2) )
public static int method(){
//Preperation (adding every given Number in the array)
for(int i=0; i<arr.length; i++){
addNumber(arr[i]);
}
//The number of elements added to the initial array
int result = 0;
//Adding (and counting) the missing numbers (Runtime O(N^2) )
for(int i=1; i<=N; i++){
if( !canCalculate[i-1] ){
addNumber(i);
result++;
}
}
return result;
}
//This Method is called whenever a new number is added to your array
//runtime O(N)
public static void addNumber( int number ){
System.out.println("Add Number: "+(number));
boolean[] newarray = new boolean[N];
newarray[number-1] = true;
//Test which values can be calculated after adding this number
//And update the array
for(int i=1; i<=N; i++){
if( canCalculate[i-1] ){
newarray[i-1] = true;
if( i + number <= N ){
newarray[i+number-1] = true;
}
}
}
canCalculate = newarray;
}
Edit: Tested the code and changed some errors (but rachel's solution seems to be better anyway)
It is a famous problem from dynamic programming. You can refer to complete solution here https://www.youtube.com/watch?v=s6FhG--P7z0
I just found a possible solution like this
public static int getNum(int n, int[] a) {
ArrayList<Integer> output = new ArrayList<Integer>();
Arrays.sort(a);
int sum = 0;
int i = 0;
while(true) {
if (i >= a.length || a[i] > sum + 1) {
output.add(sum + 1);
sum += sum + 1;
} else {
sum += a[i];
i++;
}
if (sum >= n) {
break;
}
}
return output.size();
};
And I test some cases and it looks correct.
But the one who write this didn't give us any hints and I am really confused with this one. Can anybody come up with some explanations ? Thanks!

Finding the missing number in an array with nested for loops in Java

I need to find the missing number in an array in O(n^2) time. I can rearrenge the array, so it is in order, but I have a difficult time finding the missing number without running another for loop, but I can't do that.
Here is my code:
The missing number is 3 here.
public static void main(String[] args){
int ar []={0,1,6,2,5,7,4};
int n = ar.length;
int temp = 0;
int m = 0;
for(int i = 0; i<n;i++){
for(int j = 1; j<n;j++){
if(ar[j-1] > ar[j]){
temp = ar[j-1];
ar[j-1]=ar[j];
ar[j]=temp;
if(ar[j-1]!=j-1) m=j;
}
else ar[j]=ar[j];
if(ar[j-1]!=j-1) m=j;
}
}
System.out.println(m);
}
If the input array contains all the numbers between 0 and ar.length except one missing number (as in your {0,1,6,2,5,7,4} example), you can find the missing number in linear time.
Just calculate the sum of all the numbers of the full array (the one including the missing number) - that array has ar.length + 1 elements from 0 to ar.length, so its sum is (ar.length - 0)*(ar.length + 1)/2 - and subtract from it the actual sum (which you can compute in a simple linear time loop). The difference would be the missing number.
If there are multiple missing numbers (or there may be duplicate numbers), and you need to find the first missing number, sorting the array in O(n*log(n) time and then making a single (linear time) pass over the sorted array would still be better than an O(n^2) solution.
If you can only do 2 loops, and must do 2 loops for O(n^2), then I suggest the following:
Loop thru all values (outer loop).
For each value, loop thru all values (inner loop) and find smallest value higher than current value.
If no higher value found, skip (current value is highest value)
If smallest value found is not current value + 1, then you found the missing value
How about this?
int array[] = {0,1,6,2,5,7,4};
int arrayTemp[] = array;
ArrayList<Integer> missing = new ArrayList();
Arrays.sort(arrayTemp);
for (int i=1; i<arrayTemp.length; i++) {
for (int j=arrayTemp[i-1]+1; j<arrayTemp[i]; j++) {
missing.add(j);
}
}
for (int i=arrayTemp[arrayTemp.length-1]+1; i<=arrayTemp[arrayTemp.length-1]; i++) {
missing.add(i);
}
System.out.println(missing.toString());
Output:
{0,1,6,2,5,7,4} -> [3]
{0,1,6,2,5,7,4,14} -> [3, 8, 9, 10, 11, 12, 13]

sort an array, so that first and last element will form a "pair"

I have an array of objects which I want to sort by indices in the following order. I will always have an array size to the power of 2.
Example array size: 8. Indices: [0][1] [2][3] [4][5] [6][7]
After sort: [0][7] [1][6] [2][5] [3][4]
So basically alternating between first and last element which was not sorted yet.
I already thought of a way of doing it, and I can get the "pairs" but they are in the wrong order (and I think it would not work with any other to the power of 2 array?).
Here I'm using an int array and their indices as values to make it simpler for myself.
int[] array = new int[]{0,1,2,3,4,5,6,7};
int[] sortedArray = new int[8];
for(int i = 0; i < array.length; i+=2){
sortedArray[i] = array[i];
}
for(int i = 1; i < array.length; i+=2){
sortedArray[i] = array[array.length - i];
}
Output: [0][7] [2][5] [4][3] [6][1]
You can do this with a single loop. Consider the following algorithm:
int[] array = new int[]{0,1,2,3,4,5,6,7};
int[] sortedArray = new int[8];
for(int i = 0; i < array.length; i+=2){
sortedArray[i] = array[i/2];
sortedArray[i + 1] = array[array.length - i/2 - 1];
}
System.out.println(Arrays.toString(sortedArray)); // prints [0, 7, 1, 6, 2, 5, 3, 4]
This creates the final array by setting two values at a time:
every even index of the result array is mapped with the first values of the initial array
every odd index of the result array is mapped with the last values of the initial array
Here's a recursive approach to it, and improvements exist.
Motivation: Work your way through the array until you're left with only two values to compare. Once you're done, simply print them. Otherwise, print the value and continue slicing the array. We use two index locations to help us walk through the array, as each one governs its end of the array. We cease recursion when the difference between our start and end index is 1.
Steps to guard against silly things, like a zero-length array, I leave as an exercise for the reader.
public static void arrangeArray(int[] array) {
arrangeArray(array, 0, array.length - 1);
}
private static void arrangeArray(int[] array, int startIndex, int endIndex) {
System.out.printf("[%d][%d]\t", array[startIndex], array[endIndex]);
if(endIndex - startIndex > 1) {
arrangeArray(array, startIndex + 1, endIndex - 1);
}
}
You can extend a List and then Override the way this List works with indices so 0 remains 0 but 1 becomes physically a 2 in your internal array.
If you implement this object correctly, Collections.sort() won't see the difference. Then you can add your methods to get the internal Array for whatever you have to do.
The advantage of this approach is performance. You don't have to scramble the list yourself in a secondary step.
class swap
{
public static void main(String args[])
{
int arr[]={0,1,2,3,4,5,6,7};
int sorted[]=new int[8];
int end=7;
int i=1,j;
for(int k=0;k<8;k++)
{
sorted[k]=arr[k];
}
for(j=1;j<8;j=j+2)
{
sorted[j]=arr[end];
end--;
}
for(j=2;j<8;j=j+2)
{
sorted[j]=arr[i];
i++;
}
for(int k=0;k<8;k++)
System.out.println(sorted[k]);
}
}

Categories