selection sort method for array - java

i have this method that i got from a website about selection sort that i need to check how it works :
import java.util.Arrays;
public class SelectionSort {
public static void selectionSort(int[] data, int low, int high) {
if (low < high) {
swap(data, low, findMinIndex(data, low));
selectionSort(data, low + 1, high);
}
}
public static void swap(int[] array, int index1, int index2) {
int tmp = array[index1];
array[index1] = array[index2];
array[index2] = tmp;
}
public static int findMinIndex(int[] data, int index) {
int minIndex;
if (index == data.length - 1)
return index;
minIndex = findMinIndex(data, index + 1);
if (data[minIndex] < data[index])
return minIndex;
else
return index;
}
public static void main (String[] args) {
int[] numbers = {3, 15, 1, 9, 6, 12, 21, 17, 8};
SelectionSort.selectionSort(numbers, 0, numbers.length);
System.out.println(Arrays.toString(numbers));
}
}
can you help me undrestand why is that int high get the last index of the array ?how?

In this specific code...
findMinIndex compares the element in a given index to all elements in front of it (elements with higher indices) up to the very last element of the array.
So if you have an array:
int[] a = { 7, 4, 2, 6 };
and you call findMinIndex(a, 0); it will first check to see that there is an element after index 0. That's what this part does index == data.length - 1. If there is no element after, it will simply return the index it was passed. But there obviously is an element after index 0 since the array has length 4.
Now that we've confirmed that there are elements after our index, it is time to get the index of the smallest element after index. This way we can compare the element at our index to all the elements in front of it to see which element is smallest in the range index to array.length - 1 (inclusive). This is accomplished through recursion:
minIndex = findMinIndex(data, index + 1);
So the next few calls will go like this:
findMinIndex(data, 1);
// is there an element after 1? There is. So we end up calling findMinIndex again...
findMinIndex(data, 2); // is there an element after 2? Yes. Recurse...
findMinIndex(data, 3); // is there an element after 3? No. That's the end of the array
// remember this part? it's used now to finally terminate the recursion
if (index == data.length - 1)
return index; // this equals 3
Now the recursive calls begin to unwind.
// index == 2 because the 2nd to last index is 2. remember our array has length 4 and indices 0-3.
minIndex = 3; // this is the index of the last element
if (data[3] < data[2]) { // look at our array 'a', is 6 less than 2?
return 3; // No it is not. so this is not returned
} else {
return 2; // we end up return the index (2) of the smaller element (2)
}
It unwinds again.
// index == 1
minIndex = 2; // we compared 2 and 3 and found that the element at index 2 was smaller
if (data[2] < data[1]) { // is 2 less than 4?
return 2; // yes, this is returned because the element at index 2 is less than the element at index 1
} else {
return 1; // false!
}
And one more time.
// index == 0 this is our original call! when we said findMinIndex(a, 0);
minIndex = 2;
if (data[2] < data[0]) { // is 2 less than 7?
return 2; // yes it is
} else {
return 0; // false!
}
Finally, the method will return 2. This is because of all the elements after (inclusive) index 0, the element with index 2 is the smallest.
Now let's look at selectionSort. When you first call it, you need to use this format:
selectionSort(a, 0, 4); // where 4 is the length of the array
This function also uses recursion. The swap method is self explanatory (it swaps the elements at 2 different indices). Now let's go through the recursive calls:
if (0 < 4) { // True of course
swap(a, 0, findMinIndex(a, 0));
selectionSort(data, 0 + 1, 4);
}
Remember that we found the smallest element after 0 (inclusive) had an index of 2. So the above code can be replaced with:
if (0 < 4) { // True of course
swap(a, 0, 2);
selectionSort(data, 0 + 1, 4);
}
This will change our array to {2, 4, 7, 6} because we swapped the elements at index 0 and index 2. Notice how index 0 is now the smallest element in the array with a value of 2.
Now selectionSort is called again to make sure the array is in order from least to greatest. The next call will look like this:
// low == 1 and high == 4
if (1 < 4) { // true
swap(a, 1, findMinIndex(data, 1));
selectionSort(a, 1 + 1, 4);
}
Remember our array is now {2, 4, 7, 6}. That means that the smallest element after index 1 (value of 4) is actually just 4. So the above code would be equal to:
// low == 1 and high == 4
if (1 < 4) { // true
swap(a, 1, 1);
selectionSort(a, 1 + 1, 4);
}
The swap does nothing in this case. Now the method is called recursively again.
// low == 2 and high == 4
if (2 < 4) { // true
swap(a, 2, findMinIndex(data, 2));
selectionSort(a, 2 + 1, 4);
}
Our array wasn't changed with the last swap. The smallest element after index 2 (inclusive) will be 6, which has an index of 3. That means our code above is equal to:
// low == 2 and high == 4
if (2 < 4) { // true
swap(a, 2, 3);
selectionSort(a, 2 + 1, 4);
}
Now our array becomes { 2, 4, 6, 7 }. Hooray it's in order from least to greatest! But that's not where it ends. There is another recursion call just to make sure that it's really in order.
// low == 3 and high == 4
if (3 < 4) { // true
swap(a, 3, findMinIndex(data, 3));
selectionSort(a, 3 + 1, 4);
}
Remember in findMinIndex it checks to see if there are any elements after the given index? There are no elements after index 3, so it will just return 3. That means the above code is equal to:
// low == 3 and high == 4
if (3 < 4) { // true
swap(a, 3, 3);
selectionSort(a, 3 + 1, 4);
}
This swap does nothing. And as you can see, there is still another recursion call! This will be the final one.
// low == 4 and high == 4
if (4 < 4) { // false, 4 is not less than 4
swap(a, 4, findMinIndex(a, 4)); // none of this happens
selectionSort(a, 4 + 1, 4); // no recursion
}
// finally returns void
The end.
It's a lot easier to understand selection sorts with loops as opposed to recursion.

It is the size of the array, it is used to know when is over.
Every cycle:
First: checks if any element with and index higher than low (low starts at 0) is lower and if that is the case swaps them.
Second: increase low
It stops when low is not lower than high (size of the array).
See the definition of selection sort:
http://en.wikipedia.org/wiki/Selection_sort

For anyone looking for another way to do selection sort using recursion, here is one way to do it.
//the method that will be called to sort the array recursively
public static void selectionSort(double[] arr) {
selectionSort(arr, 0);
}
//this is a recursive helper method.
//arr is the array to be sorted and index is the current index in
//the array which will be swapped with the smallest value in the
//remaining part of the array
private static void selectionSort(double[] arr, int index) {
//if index has reached the second to last value, there are
//no more values to be swapped
if (index < arr.length - 1) {
//let index, at first, be the index at which the smallest element is located
int smallestIndex = index;
//find the smallest entry in the array from i=index to i=index.length - 1
for (int i = index + 1; i < arr.length; i++) {
//if the element at i is smaller than the element at smallestIndex, then update the value of smallestIndex
if (arr[i] < arr[smallestIndex]) {
smallestIndex = i;
}
}
//swap the elements of arr[smallestIndex] and arr[index]
double t = arr[index];
arr[index] = arr[smallestIndex];
arr[smallestIndex] = t;
selectionSort(arr, index + 1);
}
}

Related

Counting triplets with smaller sum

I was trying one problem to count the number of triplets in an array whose sum is less than target value.
Input: [-1, 4, 2, 1, 3], target=5
Output: 4
Explanation: There are four triplets whose sum is less than the target:
[-1, 1, 4], [-1, 1, 3], [-1, 1, 2], [-1, 2, 3]
My Code
import java.util.*;
class TripletWithSmallerSum {
public static int searchTriplets(int[] arr, int target) {
Arrays.sort(arr);
int count = 0;
for(int i = 0; i < arr.length - 2; i++)
{
int left = i + 1;
int right = arr.length - 1;
while(left < right)
{
int targetDiff = target - arr[i] - arr[left] - arr[right];
if (targetDiff > 0)
{
count++;
right--;
}
else
{
left++;
}
}
}
// TODO: Write your code here
return count;
}
}
It produces the output of 3 where as correct value should be 4 as per the above given input. My logic was , say , x + y + z < targetSum , it implies (targetSum - (x + y + z) ) > 0. If this is true I will increase the count and then decrement the right pointer , since array is sorted. If its not true then I will increment the left pointer . But my logic does not cover the triplet {-1, 2, 3}.
Below is the correct code given by author.
import java.util.*;
class TripletWithSmallerSum {
public static int searchTriplets(int[] arr, int target) {
Arrays.sort(arr);
int count = 0;
for (int i = 0; i < arr.length - 2; i++) {
count += searchPair(arr, target - arr[i], i);
}
return count;
}
private static int searchPair(int[] arr, int targetSum, int first) {
int count = 0;
int left = first + 1, right = arr.length - 1;
while (left < right) {
if (arr[left] + arr[right] < targetSum) {
count += right - left;
left++;
} else {
right--; // we need a pair with a smaller sum
}
}
return count;
}
public static void main(String[] args) {
System.out.println(TripletWithSmallerSum.searchTriplets(new int[] { -1, 0, 2, 3 }, 3));
System.out.println(TripletWithSmallerSum.searchTriplets(new int[] { -1, 4, 2, 1, 3 }, 5));
}
}
The author has used the concept , say x + y + z < targetSum , it implies x + y < targetSum - z . But I don't get the logic of line count += right - left; . How author use this one line to capture the count. If some one can give me the intution on how to reach this inference. Also what is wrong with my code and what can I do to correct it.
A first issue with your code is that :
you only decrease the right index if the sum is inferior to the target.
However, since you have ordered your list, well you will only be entering that case until left=right.
Quick example : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], target=14
if 1+2+10 <13:
then you will only decrease 10 until you reach 2 in your array
and then you proceed to iterate to the next i-index, here going from 0 to 1.
Meaning that: you will never get the solutions in between such as [1,3,9] and all the one that follows.
I hope it helps you see where there was an error in the logic, which was not from the statement : (targetSum - (x + y + z) ) > 0 but from the action you take according to the result (True/False).
Now, I am not sure there would be an easy way to adapt your code corrctly, because the main issue here is that you have iterate over 2 indexes at once (right and left).
Now regarding your author's answer :
The trick behind :
count += right - left;
goes back to the issue you had, if i tame my example, for
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
it is basically saying that, since the array is ordered, if the sum of two integers with the right one is inferior to target, then it will also be true for all integers inferior to right :
1+2+10<14 => 1+2+9<13
And this statement is true for all integers between left and right, so instead of doing a loop for which we already have the answer, he adds to count the differences between right and left, in other words, the number of integers in your array that will be greater than left and lower than right.
Now that i have explained that, you could use the same "trick" to your code:
class TripletWithSmallerSum {
public static int searchTriplets(int[] arr, int target) {
Arrays.sort(arr);
int count = 0;
for(int i = 0; i < arr.length - 2; i++)
{
int left = i + 1;
int right = arr.length - 1;
while(left < right)
{
int targetDiff = target -( arr[i] + arr[left] + arr[right]);
if (targetDiff > 0)
{
count += right - left;
left++;
}
else
{
right--;
}
}
}
// TODO: Write your code here
return count;
}
}
I tried to be as detailed as possible, hope it helps you understand better!

Maximize the number of Elements in the Array divisible by M

I'm working on the following task.
Given an array of n integers and two integer numbers m and k.
You can add any positive integer to any element of the array such that
the total value does not exceed k.
The task is to maximize the
multiples of m in the resultant array.
Consider the following example.
Input:
n = 5, m = 2, k = 2, arr[] = [1, 2, 3, 4, 5]
Let's add 1 to the element arr[0] and 1 to arr[2] then the final array would be:
[2, 2, 4, 4, 5]
Now there are four (4) elements which are multiples of m (2).
I am not getting correct output.
My code:
public class Main {
public static void main(String[] args) {
int n = 5;
int m = 4;
int k = 3;
int count = 0;
int[] arr = {17, 8, 9, 1, 4};
for (int i = 0; i < n; i++) {
for (int j = 0; j <= k; j++) {
// check initial
if (arr[i] % m == 0) {
break;
}
// add
arr[i] = arr[i] + j;
// check again
if (arr[i] % m == 0) {
count++;
break;
}
}
}
System.out.println("Final Array : " + Arrays.toString(arr));
System.out.println("Count : " + count);
}
}
This task boils down to a well-known Dynamic programming algorithm called Knapsack problem after a couple of simple manipulations with the given array.
This approach doesn't require sorting and would be advantages when k is much smaller n.
We can address the problem in the following steps:
Iterate over the given array and count all the numbers that are already divisible by m (this number is stored in the variable count in the code below).
While iterating, for every element of the array calculate the difference between m and remainder from the division of this element by m. Which would be equal to m - currentElement % m. If the difference is smaller or equal to k (it can cave this difference) it should be added to the list (differences in the code below) and also accumulated in a variable which is meant to store the total difference (totalDiff). All the elements which produce difference that exceeds k would be omitted.
If the total difference is less than or equal to k - we are done, the return value would be equal to the number of elements divisible by m plus the size of the list of differences.
Otherwise, we need to apply the logic of the Knapsack problem to the list of differences.
The idea behind the method getBestCount() (which is an implementation Knapsack problem) boils down to generating the "2D" array (a nested array of length equal to the size of the list of differences +1, in which every inner array having the length of k+1) and populating it with maximum values that could be achieved for various states of the Knapsack.
Each element of this array would represent the maximum total number of elements which can be adjusted to make them divisible by m for the various sizes of the Knapsack, i.e. number of items available from the list of differences, and different number of k (in the range from 0 to k inclusive).
The best way to understand how the algorithm works is to draw a table on a piece of paper and fill it with numbers manually (follow the comments in the code, some intermediate variables were introduced only for the purpose of making it easier to grasp, and also see the Wiki article linked above).
For instance, if the given array is [1, 8, 3, 9, 5], k=3 and m=3. We can see 2 elements divisible by m - 3 and 9. Numbers 1, 8, 5 would give the following list of differences [2, 1, 1]. Applying the logic of the Knapsack algorithm, we should get the following table:
[0, 0, 0, 0]
[0, 0, 1, 1]
[0, 1, 1, 2]
[0, 1, 2, 2]
We are interested in the value right most column of the last row, which is 2 plus 2 (number of elements divisible by 3) would give us 4.
Note: that code provided below can dial only with positive numbers. I don't want to shift the focus from the algorithm to such minor details. If OP or reader of the post are interested in making the code capable to work with negative number as well, I'm living the task of adjusting the code for them as an exercise. Hint: only a small change in the countMultiplesOfM() required for that purpose.
That how it might be implemented:
public static int countMultiplesOfM(int[] arr, int k, int m) {
List<Integer> differences = new ArrayList<>();
int count = 0;
long totalDiff = 0; // counter for the early kill - case when `k >= totalDiff`
for (int next : arr) {
if (next % m == 0)
count++; // number is already divisible by `m` we can increment the count and from that moment we are no longer interested in it
else if (m - next % m <= k) {
differences.add(m - next % m);
totalDiff += m - next % m;
}
}
if (totalDiff <= k) { // early kill - `k` is large enough to adjust all numbers in the `differences` list
return count + differences.size();
}
return count + getBestCount(differences, k); // fire the rest logic
}
// Knapsack Algorithm implementation
public static int getBestCount(List<Integer> differences, int knapsackSize) {
int[][] tab = new int[differences.size() + 1][knapsackSize + 1];
for (int numItemAvailable = 1; numItemAvailable < tab.length; numItemAvailable++) {
int next = differences.get(numItemAvailable - 1); // next available item which we're trying to place to knapsack to Maximize the current total
for (int size = 1; size < tab[numItemAvailable].length; size++) {
int prevColMax = tab[numItemAvailable][size - 1]; // maximum result for the current size - 1 in the current row of the table
int prevRowMax = tab[numItemAvailable - 1][size]; // previous maximum result for the current knapsack's size
if (next <= size) { // if it's possible to fit the next item in the knapsack
int prevRowMaxWithRoomForNewItem = tab[numItemAvailable - 1][size - next] + 1; // maximum result from the previous row for the size = `current size - next` (i.e. the closest knapsack size which guarantees that there would be a space for the new item)
tab[numItemAvailable][size] = Math.max(prevColMax, prevRowMaxWithRoomForNewItem);
} else {
tab[numItemAvailable][size] = Math.max(prevRowMax, prevColMax); // either a value in the previous row or a value in the previous column of the current row
}
}
}
return tab[differences.size()][knapsackSize];
}
main()
public static void main(String[] args) {
System.out.println(countMultiplesOfM(new int[]{17, 8, 9, 1, 4}, 3, 4));
System.out.println(countMultiplesOfM(new int[]{1, 2, 3, 4, 5}, 2, 2));
System.out.println(countMultiplesOfM(new int[]{1, 8, 3, 9, 5}, 3, 3));
}
Output:
3 // input array [17, 8, 9, 1, 4], m = 4, k = 3
4 // input array [1, 2, 3, 4, 5], m = 2, k = 2
4 // input array [1, 8, 3, 9, 5], m = 3, k = 3
A link to Online Demo
You must change 2 line in your code :
if(arr[i]%m==0)
{
count++; // add this line
break;
}
// add
arr[i]=arr[i]+1; // change j to 1
// check again
if(arr[i]%m==0)
{
count++;
break;
}
The first is because the number itself is divisible.
and The second is because you add a number to it each time.That is wrong.
for example chenge your arr to :
int[] arr ={17,8,10,2,4};
your output is :
Final Array : [20, 8, 16, 8, 4]
and That is wrong because 16-10=6 and is bigger than k=3.
I believe the problem is that you aren't processing the values in ascending order of the amount by which to adjust.
To solve this I started by using a stream to preprocess the array. This could be done using other methods.
map the values to the amount to make each one, when added, divisible by m.
filter out those that equal to m' (already divisible by m`)
sort in ascending order.
Once that is done. Intialize max to the difference between the original array length and the processed length. This is the number already divisible by m.
As the list is iterated
check to see if k > amount needed. If so, subtract from k and increment max
otherwise break out of the loop (because of the sort, no value remaining can be less than k)
public static int maxDivisors(int m, int k, int[] arr) {
int[] need = Arrays.stream(arr).map(v -> m - v % m)
.filter(v -> v != m).sorted().toArray();
int max = arr.length - need.length;
for (int val : need) {
if (k >= val) {
k -= val;
max++;
} else {
break;
}
}
return max;
}
int m = 4;
int k = 3;
int[] arr ={17,8,9,1,4};
int count = maxDivisors(m, k, arr);
System.out.println(count);
prints
3

Find if an array can produce a sum n with k number of elements

Given an int array that may contain duplicates. I need to find out whether the array can produce a sum with k elements?
I'm trying to use recursion for now but I'm not getting anywhere at the moment. I have a problem with getting the base-case right.
static boolean groupSum(int[] nums, int k, int sum) {
if (sum == 0)
return true;
if (k > nums.length || sum != 0)
return false;
if (groupSum(nums, k, sum - nums[k - k] - nums[k - k + 1] - nums[k - k + 2]))
return true;
if (groupSum(nums, k, sum - nums[k - k + 1] - nums[k - k + 2] - nums[k - k + 3]))
return true;
else
return false;
}
The base case of your recursive method is incorrect: sum == 0 isn't a sufficient condition you also have to check whether k == 0. If the sum is 0 but you still have to use a few more elements then the result true is incorrect.
The recursive part of the method has some mistakes in it as well. The number of elements summed up k never gets decremented.
Also, you have to track a position in the array. I mean you need to iterate over the array. And while iterating for each element there are only two options: apply it (decrement the k and subtract current value from the sum) or discard it. In both cases, you have to increment the position that you are passing as an argument.
That is how it could be fixed:
public static boolean groupSum(int[] nums, int k, int pos, int sum) {
if (sum == 0 && k == 0) {
return true;
}
if (sum < 0) {
return false;
}
boolean result = false;
for (int i = pos; i < nums.length; i++) {
boolean takeElement = groupSum(nums, k - 1, pos + 1, sum - nums[i]);
boolean discardElement = groupSum(nums, k, pos + 1, sum);
result = takeElement || discardElement;
if (result) { // a combination that yield the target sum was found
break;
}
}
return result;
}
There's another option how to implement this method. But caution: it will be slower and significantly increases memory consumption.
This approach requires creating a copy of the given array with a length decremented by 1 at each recursive method call and pass it as an argument. In this version, an element at position 0 is always used when the method is called, therefore it doesn't require to track the position in the array. The main logic remains the same: a new element can be used either to contribute the sum or can be discarded.
public static boolean groupSum(int[] nums, int k, int sum) {
if (sum == 0 && k == 0) {
return true;
}
if (sum < 0 || nums.length == 0) {
return false;
}
boolean takeElement = groupSum(Arrays.copyOfRange(nums, 1, nums.length), k - 1, sum - nums[0]);
boolean discardElement = groupSum(Arrays.copyOfRange(nums, 1, nums.length), k, sum);
return takeElement || discardElement;
}
public static void main(String[] args) {
// sum of 1, 2, 3, 4, 5 yields 15 - expected true
System.out.println(groupSum(new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9}, 5, 0, 15));
// it's impossible with only one element - expected false
System.out.println(groupSum(new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9}, 1, 0, 10));
// sum of 4, 5, 6 yields 15 - expected true
System.out.println(groupSum(new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9}, 3, 0, 15));
}
output
true
false
true

Add one in a number of arraylist

public class Solution {
public ArrayList<Integer> plusOne(ArrayList<Integer> A) {
int n = A.size();
// Add 1 to last digit and find carry
A.set(n - 1, A.get(n - 1) + 1);
int carry = A.get(n - 1) / 10;
A.set(n - 1, A.get(n - 1) % 10);
// Traverse from second last digit
for (int i = n - 2; i >= 0; i--) {
if (carry == 1) {
A.set(i, A.get(i) + 1);
carry = A.get(i) / 10;
A.set(i, A.get(i) % 10);
}
}
// If carry is 1, we need to add
// a 1 at the beginning of vector
if (carry == 1)
A.add(0, 1);
return A;
}
}
Question is:
Given a non-negative number represented as an array of digits,
add 1 to the number ( increment the number represented by the digits ).
The digits are stored such that the most significant digit is at the head of the list.
Example:
If the vector has [1, 2, 3]
the returned vector should be [1, 2, 4]
as 123 + 1 = 124.
Wrong Answer. Your program's output doesn't match the expected output. You can try testing your code with custom input and try putting debug statements in your code.
Your submission failed for the following input:
A : [ 0, 0, 4, 4, 6, 0, 9, 6, 5, 1 ]
Your function returned the following :
0 4 4 6 0 9 6 5 2
The expected returned value :
4 4 6 0 9 6 5 2
Use below method
private ArrayList<Integer> recursiveCheckZero() {
if (arrayList.get(0) == 0) {
arrayList.remove(0);
recursiveCheckZero();
} else {
return arrayList;
}
}
This method will be used to zero at first position, it would be called recursively until all zeros get removed. and when there will be no zero at first position it will return final ArrayList of integers as actual result
int sum=0;
int carry=0;
int i=0;
while (i < A.size() - 1 && A.get(i) == 0) {
A.remove(i); //remove all zeroes in front
}
for(i=A.size()-1;i>=0;i--)
{
int n=A.get(i);
sum=n+carry;
if(i==A.size()-1)
{
sum = sum+1;
}
carry=sum/10;
sum=sum%10;
A.set(i,sum);
}
if (carry !=0)
A.add(0,1);
return A;

Counting down a variable length array of integers to Zero in Java

I have an array that contains the total number of lines in 3 files. Example: [3,4,5]. I would like to produce a sequence of numbers that count that array down to zero in a methodical way giving me every combination of lines in the three files. This example uses 3 files/length-3 array, but the algorithm should be able to work an array with any arbitrary length.
For the example above, the solution would look like:
[3,4,5] (line 3 from file 1, line 4 from file 2, line 5 from file 3)
[3,4,4]
[3,4,3]
[3,4,2]
[3,4,1]
[3,4,0]
[3,3,5]
[3,3,4]
[3,3,3]
[3,3,2]
and so on...
My first attempt at producing an algorithm for this recursively decrements a position in the array, and when that position reaches zero - decrements the position before it. However I'm not able to keep the decrementing going for farther than the last two positions.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class FilePositionGenerator {
public static void main(String[] args) {
int[] starterArray = {2, 2, 2};
int[] counters = starterArray.clone();
List<Integer> results = new ArrayList<Integer>();
FilePositionGenerator f = new FilePositionGenerator();
f.generateFilePositions(starterArray, counters, (starterArray.length - 1), results);
}//end main
void generateFilePositions(int[] originalArray, int[] modifiedArray, int counterPosition, List<Integer> results) {
if (modifiedArray[counterPosition] == 0 && counterPosition > 0) {
modifiedArray[counterPosition] = originalArray[counterPosition];
counterPosition = counterPosition - 1;
} else {
modifiedArray[counterPosition] = modifiedArray[counterPosition] - 1;
System.out.println(Arrays.toString(modifiedArray));
generateFilePositions(originalArray, modifiedArray, counterPosition, results);
}
}
}
I understand that to deal with a variable length array, the algorithm must be recursive, but I'm having trouble thinking it through. So I decided to try a different approach.
My second attempt at producing an algorithm uses a dual pointer method that keeps a pointer on the current countdown position[the rightmost position], and a pointer to the next non-rightmost position(pivotPointer) that will be decremented when the rightmost position reaches zero. Like so:
import java.util.Arrays;
class DualPointer {
public static void main(String[] args) {
int[] counters = {2, 2, 2}; // initialize the problem set
int[] original = {2, 2, 2}; // clone a copy to reset the problem array
int[] stopConditionArray = {0, 0, 0}; // initialize an object to show what the stopCondition should be
int pivotLocation = counters.length - 1; // pointer that starts at the right, and moves left
int counterLocation = counters.length - 1; // pointer that always points to the rightmost position
boolean stopCondition = false;
System.out.println(Arrays.toString(counters));
while (stopCondition == false) {
if (pivotLocation >= 0 && counterLocation >= 0 && counters[counterLocation] > 0) {
// decrement the rightmost position
counters[counterLocation] = counters[counterLocation] - 1;
System.out.println(Arrays.toString(counters));
} else if (pivotLocation >= 0 && counters[counterLocation] <= 0) {
// the rightmost position has reached zero, so check the pivotPointer
// and decrement if necessary, or move pointer to the left
if (counters[pivotLocation] == 0) {
counters[pivotLocation] = original[pivotLocation];
pivotLocation--;
}
counters[pivotLocation] = counters[pivotLocation] - 1;
counters[counterLocation] = original[counterLocation]; // reset the rightmost position
System.out.println(Arrays.toString(counters));
} else if (Arrays.equals(counters, stopConditionArray)) {
// check if we have reached the solution
stopCondition = true;
} else {
// emergency breakout of infinite loop
stopCondition = true;
}
}
}
}
Upon running, you can see 2 obvious problems:
[2, 2, 2]
[2, 2, 1]
[2, 2, 0]
[2, 1, 2]
[2, 1, 1]
[2, 1, 0]
[2, 0, 2]
[2, 0, 1]
[2, 0, 0]
[1, 2, 2]
[1, 2, 1]
[1, 2, 0]
[0, 2, 2]
[0, 2, 1]
[0, 2, 0]
Number one, the pivotPointer does not decrement properly when the pivotPointer and currentCountdown are more than one array cell apart. Secondly, there is an arrayIndexOutOfBounds at the line counters[pivotLocation] = counters[pivotLocation] - 1; that if fixed,
breaks the algorithm from running properly alltogether.
Any help would be appreciated.
I'll suggest a different approach.
The idea in recursion is to reduce the size of the problem in each recursive call, until you reach a trivial case, in which you don't have to make another recursive call.
When you first call the recursive method for an array of n elements, you can iterate in a loop over the range of values of the last index (n-1), make a recursive call to generate all the combinations for the array of the first n-1 elements, and combine the outputs.
Here's some partial Java/ partial pseudo code :
The first call :
List<int[]> output = generateCombinations(inputArray,inputArray.length);
The recursive method List<int[]> generateCombinations(int[] array, int length) :
List<int[]> output = new ArrayList<int[]>();
if length == 0
// the end of the recursion
for (int i = array[length]; i>=0; i--)
output.add (i)
else
// the recursive step
List<int[]> partialOutput = generateCombinations(array, length - 1)
for (int i = array[length]; i>=0; i--)
for (int[] arr : partialOutput)
output.add(arr + i)
return output
The recursive method returns a List<int[]>. This means that in "output.add (i)" you should create an int array with a single element and add it to the list, while in output.add(arr + i) you'll create an array of arr.length+1 elements, and copy to it the elements of arr followed by i.
The fun thing about recursion is that you can have it do exactly what you want it to. In this case, for each number at index i of your array of counts, we want to combine it with each number at index i + 1 until we reach the end of the array. The trick is not to return to index i once you've run through all the options for it.
JavaScript code:
var arr = [3,4,5];
var n = arr.length;
function f(cs,i){
// base case
if (i == n){
console.log(cs.join(','));
return;
}
// otherwise
while (cs[i] >= 0){
// copy counts
_cs = cs.slice();
// recurse
f(_cs,i + 1);
// change number at index i
cs[i]--;
}
}
f(arr,0);

Categories