I must implement a recursive method merge(long[] arr, int i) which multiplies adjacent elements if they have the same value, starting at index i.
Example:
merge({1, 2, 2, 4}, 0)
should produce an array like this:
{1, 4, 4}
If there are multiple (n) occurrences of a number {1, 2, 2, 2, 2, 5}, all of these must be multiplied together: {1, 16, 5}.
A number which has already been merged can not be merged again {1, 4, 4, 16} -> {1, 16, 16}.
All this must be achieved by using only this one method merge and having exactly one recursive call per element in the original array.
This is a working implementation using recursion and loops:
public static long[] merge(long[] ns, int i) {
final long[] EMPTY_LONG_ARRAY = {};
if (i < 0) {
return merge(ns, 0, m); // if i negative, start at 0
} else if (i >= ns.length) {
return EMPTY_LONG_ARRAY; // if out of bounds, return empty array
} else if (i == ns.length - 1) {
return ns; // base case
} else { // recursion in here
if (ns[i] == ns[i + 1]) { // if next long is equal
int occurences = 1; // first occurence
for (int j = i; j < ns.length - 1; j++) {
if (ns[j] == ns[j + 1])
occurences++;
else
break;
} // add next occurences
long[] newArray = new long[ns.length - occurences + 1]; // new array is (occurences-1) shorter
for (int j = 0; j < newArray.length; j++) { // fill new array
if (j < i) {
newArray[j] = ns[j]; // left of i: values stay the same
} else if (j > i) {
newArray[j] = ns[j + occurences - 1]; // pull values right of i (occurences-1) to the left
} else {
int counter = occurences;
long mergedValue = ns[j];
while (counter > 1) {
mergedValue *= ns[j];
counter--;
}
newArray[j] = mergedValue; // at j: value is ns[j]^occurences
}
}
if (i == ns.length - 1)
return merge(newArray, i, m);
else
return merge(newArray, i + 1, m); // if bounds permit it, jump to next number
} else {
return merge(ns, i + 1, m); // nothing to merge, go one step forward
}
}
This implementation produces the correct result, however, the recursion depth is wrong (needs to be one recursive call per element in original array ns[]).
I'm sure there is a genius out here who can solve this using linear recursion.
Lets transform your loop into a recursive call. The only reason to do this is that the assignment asks for it - it is not more readable (at least to me), and it is actually slower. People usually want to go in the other direction for efficiency reasons: from recursion to loops.
First, an annotated version of your code:
public static long[] merge(long[] ns, int i) { // i not needed, but useful for recursion
long[] out = new long[ns.length]; // for result; allocate only once
for (int j = i; j < ns.length; j++) { // main loop, condition is "j == length"
int occurences = 0;
for (int k = i; k < ns.length; k++) { // inner loop - can avoid!
if (ns[j] == ns[k]) {
occurences++;
}
}
out[j] = (long) Math.pow(ns[j], occurences); // updating the result
}
// remove additional elements
return out; // this does not remove elements yet!
}
First, let me rewrite that to be more efficient. Since duplicates are only removed if they are next to each other, you do not need the inner loop, and can write this instead:
public static long[] merge(long[] ns) {
long[] out = new long[ns.length];
int oSize = 0; // index of element-after-last in array out
long prev = ns[0]; // previous element in ns; initial value chosen carefully
out[0] = 1; // this make the 1st iteration work right, not incrasing oSize
for (int i=0; i<ns.length; i++) {
long current = ns[i];
if (current == prev) {
out[oSize] *= current; // accumulate into current position
} else {
oSize ++; // generate output
out[oSize] = current; // reset current and prev
prev = current;
}
}
// generate final output, but do not include unused elements
return Arrays.copyOfRange(out, 0, oSize+1);
}
Assuming this works (and beware - I have not tested it), I will now transform it into tail recursion. There will be 2 parts: a driver code (everything not in the loop), and the recursive code (the loopy part).
public static long[] merge(long[] ns) {
long[] out = new long[ns.length];
int oSize = 0;
long prev = ns[0];
out[0] = 1;
int i=0;
recursiveMerge(ns, i, out, oSize, prev); // recursion!
return Arrays.copyOfRange(out, 0, oSize+1);
}
public static void recursiveMerge(long[] ns, int i, long[] out, int oSize, long prev) {
if (i == n) return; // check "loop" termination condition
// copy-pasted loop contents
long current = ns[i];
if (current == prev) {
out[oSize] *= current; // accumulate into current position
} else {
oSize ++; // generate output
out[oSize] = current; // reset current and prev
prev = current;
}
// next loop iteration is now a recursive call. Note the i+1
recursiveMerge(ns, i+1, out, oSize, prev);
}
The general idea is to pass all state as arguments to your recursive function, and check loop termination at the start, put the loop code in the middle, and at the very end, make a recursive call for the next iteration.
I have an array containing some duplicate elements like this :
find the first duplicate number for which the second occurrence has the minimal index. In other words, if there are more than 1 duplicated numbers, return the number for which the second occurrence has a smaller index than the second occurrence of the other number does. If there are no such elements, return -1
For a = [2, 1, 3, 5, 3, 2], the output should be
firstDuplicate(a) = 3.
There are 2 duplicates: numbers 2 and 3. The second occurrence of 3 has a smaller index than the second occurrence of 2 does, so the answer is 3.
I tried this :
int firstDuplicate(int[] a) {
Set<Integer> set = new HashSet<>();
Map<Integer, Integer> hm = new HashMap<Integer,Integer>();
Map.Entry<Integer, Integer> min = null;
for(int i=0;i<a.length;i++){
// if(!hm.containsKey(a[i]))
hm.put(a[i],i);
}
for(Map.Entry<Integer,Integer> entry : hm.entrySet()){
if(min == null || entry.getValue() < min.getValue()){
min = entry;
}
}
return min == null ? new Integer(-1) : min.getKey();
}
It's not working out, but I got another solution online which is like this :
int firstDuplicate(int[] a) {
Set<Integer> set = new HashSet<>();
Map<Integer, Integer> hm = new HashMap<Integer,Integer>();
Map.Entry<Integer, Integer> min = null;
for(int i=0;i<a.length;i++){
if(set.add(a[i])==false && !hm.containsKey(a[i]))
hm.put(a[i],i);
}
for(Map.Entry<Integer,Integer> entry : hm.entrySet()){
if(min == null || entry.getValue() < min.getValue()){
min = entry;
}
}
return min == null ? new Integer(-1) : min.getKey();
}
Can anyone please explain me the use of Hashset here, as it doesn't allow the duplicates so how that if condition will be workable.
The reason your first attempt failed is that you add the array elements as keys to the Map without checking if they are already there, which means you can't know if there are any duplicates by the time you finish populating the Map.
The alternative code you found does something different. It uses the Set to determine if the current array element already appeared earlier in the array, and if that's the case, it adds it as key to the Map only if it's not already there. This means that the Map will only contain elements that appear multiple times in the array, and the index associated with each element is the occurrence of the first duplicate. I.e. for the array {2, 1, 3, 5, 3, 2}, the Map will contain {2=5, 3=4}. Then it will return the key having the smallest value (which corresponds with the index of the first duplicate).
However, the Map is unnecessary, since you only need to find one duplicate, not all of them. Use the Set to locate the first duplicate and return it:
int firstDuplicate(int[] a)
{
Set<Integer> set = new HashSet<>();
for(int i=0;i<a.length;i++){
if(!set.add(a[i])) {
return a[i];
}
}
return -1; // no duplicates found
}
This relies on set.add() returning false if the Set already contains the element you wish to add. Once it returns false for the first time, you found the first duplicate.
I would strongly recommend you to try this to get the correct results
you can make it more efficient time complexity O(n)
int firstDuplicate(int[] a){
int n = a.length;
for(int i=0; i<n; i++)
{
if(a[Math.abs(a[i])-1]<0) return Math.abs(a[i]);
else a[Math.abs(a[i])-1] = - a[Math.abs(a[i])-1];
}
return -1;
}
int firstDuplicate(int[] a){
int n = a.length;
for(int i=0; i<n; i++)
{
if(a[Math.abs(a[i])-1]<0) return Math.abs(a[i]);
else a[Math.abs(a[i])-1] = - a[Math.abs(a[i])-1];
}
return -1;
}
I will explain why and how this one works.
It's important that this constrain: 1 ≤ a[i] ≤ a.length is present, meaning that in an array like this: a = [2,8,2] this algorithm WILL NOT work because 8 is bigger than a.length in this case 3.
You'll find the explanation here as well:
Hashmap
This solution follows the idea of a hashmap. Another structure where you count hash[arr[i]-1]++ the number of occurrences for any given index i in the array. Example:
If you have arr[2,1,3,5,3,2] hashmap will begin in an 6 zero array: hashmap[0,0,0,0,0,0] because that's the size of arr. As the algorithm progress it will sum +1 in the position arr[i]-1. It's using the value as the index of the sum. At then end you get: arr[1,2,2,0,1,0].
This has O(n) in time complexity because it runs the full arr, and O(n) in time because it runs the array at least 1 time.
Without Hashmap
The idea of the algorithm above is that you don't need the extra structure of a hashmap but can use the same array to count the frequency. This might lead to a problem. Let i-th element be a or (arr[i]=a) then the count should be stored at arr[arr[i]-1] or (arr[a-1]), but when the frequency will be stored the element will be lost.
Example iteration:
a[2,1,3,5,3,2] -> a[2,1,3,5,3,2]
a[2,1,3,5,3,2] -> a[1,1,3,5,3,2]
a[1,1,3,5,3,2] -> a[1,1,1,5,3,2]
a[1,1,1,5,3,2] -> a[1,1,1,5,1,2] As you can see we lost the value of 3 when we read 5 as it stored the frequency in arr[arr[4]-1] or (arr[5-1]).
Solve the missing problem
To solve this problem first we put replace the i-th element with arr[arr[i]-1] or (arr[a-1]) then put -1 at array arr[arr[i]-1] or (arr[a-1]).
The algorithm:
Traverse the array from start to end.
For each element check if the element is less than or equal to zero or not. If negative or zero skip the element as it is frequency.
If an element (a = arr[i] – 1) is positive, then check if arr[a] is positive or not. If positive then that means it is the first occurrence of a in the array and replace arr[i] with arr[a], and assign arr[a] = -1. If arr[a] is negative, then it is not the first occurrence, then update arr[a] as arr[a]-- and update arr[i] as arr[i] = 0. You use an auxiliary value to save arr[a] that will be used in the next iteration.
Again, traverse the array and print i+1 as value and arr[i] as frequency.
Example iteration:
a[2,1,3,5,3,2] -> a[1,1,3,5,3,2] -> a[1,-1,3,5,3,2]
a[1,-1,3,5,3,2] -> a[1,-1,3,5,3,2] -> a[1,-1,-1,5,3,2]
a[1,-1,-1,5,3,2] -> a[1,-1,-1,0,3,2]
a[1,-1,-1,0,3,2] -> a[1,-1,-1,0,-1,2] -> a[1,-1,-2,0,-1,2]
a[1,-1,-2,0,-1,2] -> a[1,-1,-2,0,-1,0]
a[1,-1,-2,0,-1,0] -> a[1,-2,-2,0,-1,0]
firstDuplicate
After knowing this we can now grasp how firstDuplicate works. The idea is not to count the frequency but instead just print the index that has already a negative in frequency. When we get a negative frequency we return.
So running the algorithm we get:
With if(a[2-1]<0) or if(1<0) this comparation is between arr[arr[0]-1] or (arr[1]) and 0 so we don't return. a[2,1,3,5,3,2] -> a[2,-1,3,5,3,2]
With if(a[1-1]<0) or if(2<0) we don't return a[2,-1,3,5,3,2] -> a[-1,-1,3,5,3,2].
With if(a[3-1]<0) or if(3<0) we don't return. a[-1,-1,3,5,3,2] -> a[-2,-1,-3,5,3,2]
With if(a[5-1]<0) or if(3<0) we don't return. a[-2,-1,-3,5,3,2] -> a[-2,-1,-3,5,-3,2]
With if(a[3-1]<0) or if(-3<0) we return.
All of this is based on the idea that element-1 is the index.
You can use java 8 with lambda and stream.
Here is the code in one line :
Set<Integer> allItems = new HashSet<>();
Arrays.stream(a).filter(i -> !allItems.add(i)).findFirst().orElse(-1)
it returns what you expect
There are two ways to implement this problem, by using a HashSet with time complexity o(n) and by using nested loops o(n2)
for(int i = 0; i < a.length; i++){
for(int j = i +1; j < a.length; j++){
if(a[i] == a[j]){
System.out.println(a[i]);
return;
}
}
}
Or you can make it more efficient time complexity O(n)
int index -1;
Set<Integer> hashSet = new HashSet<Integer>();
for(int i = a.length-1; i >= 0; i--){
if(hashSet.contains(a[i])){
index = i;
}else{
hashSet.add(a[i]);
}
}
System.out.println(a[index]);
int firstDuplicate(int[] a)
{
int DupIndex = 0;
int DupValue = 0;
for (int i = 0; i < a.Length; i++)
{
for (int j = i + 1; j < a.Length; j++)
{
if (a[i] == a[j])
{
if (j < DupIndex)
{
DupIndex = j;
DupValue = a[i];
}
else if (DupIndex == 0)
{
DupIndex = j;
DupValue = a[i];
}
}
};
};
return (DupValue == 0) ? -1 : DupValue;
}
public static void main(String[] args){
int array[]={2, 1, 3, 5, 3, 2};
int tempArray[]=new int[array.length];
int index=0;
while(index< array.length){
if(++(tempArray[array[index]])==2)
break;
index++;
}
if(index> array.length){
System.out.println("No Duplicate");
}else {
System.out.println("First Duplicate " + array[index]);
}
}
Use counting sort, sweet and simple :)
Java implementation
Time complexity O(n) -- Linear
Space Complexity O(n) -- Linear
//Approach
//run a loop and try to insert it into a map.
//check if map contains key for arr[nextValue]
//if contains key, break loop and return value.
//if not, keep on adding in the map.
import java.util.HashMap;
import java.util.Map;
public class ReturnFirstRecurringCharacter {
public static void main(String[] args) {
int[] arr1 = {2,5,5,2};
Integer recurringNumber = checkForRecurringNumber(arr1);
if (recurringNumber != null) {
System.out.println(recurringNumber);
} else {
System.out.println("Undefined");
}
}
private static Integer checkForRecurringNumber(int[] arr1) {
try {
if (arr1 != null) {
Map<Integer, Integer> dataMap = new HashMap<>();
for (int i = 0; i < arr1.length; i++) {
if (dataMap.containsKey(arr1[i])) {
return arr1[i];
}
dataMap.put(arr1[i], i);
}
}
} catch (Exception e) {
System.out.println(e);
e.getStackTrace();
}
return null;
}
}
JS solution:
function solution(a) {
const map = {};
for(let i=0; i<a.length; i++) {
if(map[a[i]]) {
if(map[a[i]][0] === 1) {
map[a[i]][0]++ ;
map[a[i]][1] = i;
}
} else {
map[a[i]] = [1, i];
}
}
const data = Object.keys(map).filter(key => map[key][0] == 2).map(el => parseInt(el));
let smallest = Infinity;
let smallestData = -1;
for(let i=0; i<data.length; i++) {
if(map[data[i]][1] < smallest) {
smallest = map[data[i]][1];
smallestData = data[i];
}
}
return smallestData;
}
Solution in Javascript
function solution(a) {
let i = -1;
while (++i < a.length)
if (a.indexOf(a[i]) !== i)
return a[i];
return -1;
}
console.log(solution([2, 1, 3, 5, 3, 2])); // 3
console.log(solution([2, 2])); // 2
console.log(solution([2, 4, 3, 5, 1])); // -1
I'm working on a puzzle that involves analyzing all size k subsets and figuring out which one is optimal. I wrote a solution that works when the number of subsets is small, but it runs out of memory for larger problems. Now I'm trying to translate an iterative function written in python to java so that I can analyze each subset as it's created and get only the value that represents how optimized it is and not the entire set so that I won't run out of memory. Here is what I have so far and it doesn't seem to finish even for very small problems:
public static LinkedList<LinkedList<Integer>> getSets(int k, LinkedList<Integer> set)
{
int N = set.size();
int maxsets = nCr(N, k);
LinkedList<LinkedList<Integer>> toRet = new LinkedList<LinkedList<Integer>>();
int remains, thresh;
LinkedList<Integer> newset;
for (int i=0; i<maxsets; i++)
{
remains = k;
newset = new LinkedList<Integer>();
for (int val=1; val<=N; val++)
{
if (remains==0)
break;
thresh = nCr(N-val, remains-1);
if (i < thresh)
{
newset.add(set.get(val-1));
remains --;
}
else
{
i -= thresh;
}
}
toRet.add(newset);
}
return toRet;
}
Can anybody help me debug this function or suggest another algorithm for iteratively generating size k subsets?
EDIT: I finally got this function working, I had to create a new variable that was the same as i to do the i and thresh comparison because python handles for loop indexes differently.
First, if you intend to do random access on a list, you should pick a list implementation that supports that efficiently. From the javadoc on LinkedList:
All of the operations perform as could be expected for a doubly-linked
list. Operations that index into the list will traverse the list from
the beginning or the end, whichever is closer to the specified index.
An ArrayList is both more space efficient and much faster for random access. Actually, since you know the length beforehand, you can even use a plain array.
To algorithms: Let's start simple: How would you generate all subsets of size 1? Probably like this:
for (int i = 0; i < set.length; i++) {
int[] subset = {i};
process(subset);
}
Where process is a method that does something with the set, such as checking whether it is "better" than all subsets processed so far.
Now, how would you extend that to work for subsets of size 2? What is the relationship between subsets of size 2 and subsets of size 1? Well, any subset of size 2 can be turned into a subset of size 1 by removing its largest element. Put differently, each subset of size 2 can be generated by taking a subset of size 1 and adding a new element larger than all other elements in the set. In code:
processSubset(int[] set) {
int subset = new int[2];
for (int i = 0; i < set.length; i++) {
subset[0] = set[i];
processLargerSets(set, subset, i);
}
}
void processLargerSets(int[] set, int[] subset, int i) {
for (int j = i + 1; j < set.length; j++) {
subset[1] = set[j];
process(subset);
}
}
For subsets of arbitrary size k, observe that any subset of size k can be turned into a subset of size k-1 by chopping of the largest element. That is, all subsets of size k can be generated by generating all subsets of size k - 1, and for each of these, and each value larger than the largest in the subset, add that value to the set. In code:
static void processSubsets(int[] set, int k) {
int[] subset = new int[k];
processLargerSubsets(set, subset, 0, 0);
}
static void processLargerSubsets(int[] set, int[] subset, int subsetSize, int nextIndex) {
if (subsetSize == subset.length) {
process(subset);
} else {
for (int j = nextIndex; j < set.length; j++) {
subset[subsetSize] = set[j];
processLargerSubsets(set, subset, subsetSize + 1, j + 1);
}
}
}
Test code:
static void process(int[] subset) {
System.out.println(Arrays.toString(subset));
}
public static void main(String[] args) throws Exception {
int[] set = {1,2,3,4,5};
processSubsets(set, 3);
}
But before you invoke this on huge sets remember that the number of subsets can grow rather quickly.
You can use
org.apache.commons.math3.util.Combinations.
Example:
import java.util.Arrays;
import java.util.Iterator;
import org.apache.commons.math3.util.Combinations;
public class tmp {
public static void main(String[] args) {
for (Iterator<int[]> iter = new Combinations(5, 3).iterator(); iter.hasNext();) {
System.out.println(Arrays.toString(iter.next()));
}
}
}
Output:
[0, 1, 2]
[0, 1, 3]
[0, 2, 3]
[1, 2, 3]
[0, 1, 4]
[0, 2, 4]
[1, 2, 4]
[0, 3, 4]
[1, 3, 4]
[2, 3, 4]
Here is a combination iterator I wrote recetnly
package psychicpoker;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import static com.google.common.base.Preconditions.checkArgument;
public class CombinationIterator<T> implements Iterator<Collection<T>> {
private int[] indices;
private List<T> elements;
private boolean hasNext = true;
public CombinationIterator(List<T> elements, int k) throws IllegalArgumentException {
checkArgument(k<=elements.size(), "Impossible to select %d elements from hand of size %d", k, elements.size());
this.indices = new int[k];
for(int i=0; i<k; i++)
indices[i] = k-1-i;
this.elements = elements;
}
public boolean hasNext() {
return hasNext;
}
private int inc(int[] indices, int maxIndex, int depth) throws IllegalStateException {
if(depth == indices.length) {
throw new IllegalStateException("The End");
}
if(indices[depth] < maxIndex) {
indices[depth] = indices[depth]+1;
} else {
indices[depth] = inc(indices, maxIndex-1, depth+1)+1;
}
return indices[depth];
}
private boolean inc() {
try {
inc(indices, elements.size() - 1, 0);
return true;
} catch (IllegalStateException e) {
return false;
}
}
public Collection<T> next() {
Collection<T> result = new ArrayList<T>(indices.length);
for(int i=indices.length-1; i>=0; i--) {
result.add(elements.get(indices[i]));
}
hasNext = inc();
return result;
}
public void remove() {
throw new UnsupportedOperationException();
}
}
I've had the same problem today, of generating all k-sized subsets of a n-sized set.
I had a recursive algorithm, written in Haskell, but the problem required that I wrote a new version in Java.
In Java, I thought I'd probably have to use memoization to optimize recursion. Turns out, I found a way to do it iteratively. I was inspired by this image, from Wikipedia, on the article about Combinations.
Method to calculate all k-sized subsets:
public static int[][] combinations(int k, int[] set) {
// binomial(N, K)
int c = (int) binomial(set.length, k);
// where all sets are stored
int[][] res = new int[c][Math.max(0, k)];
// the k indexes (from set) where the red squares are
// see image above
int[] ind = k < 0 ? null : new int[k];
// initialize red squares
for (int i = 0; i < k; ++i) { ind[i] = i; }
// for every combination
for (int i = 0; i < c; ++i) {
// get its elements (red square indexes)
for (int j = 0; j < k; ++j) {
res[i][j] = set[ind[j]];
}
// update red squares, starting by the last
int x = ind.length - 1;
boolean loop;
do {
loop = false;
// move to next
ind[x] = ind[x] + 1;
// if crossing boundaries, move previous
if (ind[x] > set.length - (k - x)) {
--x;
loop = x >= 0;
} else {
// update every following square
for (int x1 = x + 1; x1 < ind.length; ++x1) {
ind[x1] = ind[x1 - 1] + 1;
}
}
} while (loop);
}
return res;
}
Method for the binomial:
(Adapted from Python example, from Wikipedia)
private static long binomial(int n, int k) {
if (k < 0 || k > n) return 0;
if (k > n - k) { // take advantage of symmetry
k = n - k;
}
long c = 1;
for (int i = 1; i < k+1; ++i) {
c = c * (n - (k - i));
c = c / i;
}
return c;
}
Of course, combinations will always have the problem of space, as they likely explode.
In the context of my own problem, the maximum possible is about 2,000,000 subsets. My machine calculated this in 1032 milliseconds.
Inspired by afsantos's answer :-)... I decided to write a C# .NET implementation to generate all subset combinations of a certain size from a full set. It doesn't need to calc the total number of possible subsets; it detects when it's reached the end. Here it is:
public static List<object[]> generateAllSubsetCombinations(object[] fullSet, ulong subsetSize) {
if (fullSet == null) {
throw new ArgumentException("Value cannot be null.", "fullSet");
}
else if (subsetSize < 1) {
throw new ArgumentException("Subset size must be 1 or greater.", "subsetSize");
}
else if ((ulong)fullSet.LongLength < subsetSize) {
throw new ArgumentException("Subset size cannot be greater than the total number of entries in the full set.", "subsetSize");
}
// All possible subsets will be stored here
List<object[]> allSubsets = new List<object[]>();
// Initialize current pick; will always be the leftmost consecutive x where x is subset size
ulong[] currentPick = new ulong[subsetSize];
for (ulong i = 0; i < subsetSize; i++) {
currentPick[i] = i;
}
while (true) {
// Add this subset's values to list of all subsets based on current pick
object[] subset = new object[subsetSize];
for (ulong i = 0; i < subsetSize; i++) {
subset[i] = fullSet[currentPick[i]];
}
allSubsets.Add(subset);
if (currentPick[0] + subsetSize >= (ulong)fullSet.LongLength) {
// Last pick must have been the final 3; end of subset generation
break;
}
// Update current pick for next subset
ulong shiftAfter = (ulong)currentPick.LongLength - 1;
bool loop;
do {
loop = false;
// Move current picker right
currentPick[shiftAfter]++;
// If we've gotten to the end of the full set, move left one picker
if (currentPick[shiftAfter] > (ulong)fullSet.LongLength - (subsetSize - shiftAfter)) {
if (shiftAfter > 0) {
shiftAfter--;
loop = true;
}
}
else {
// Update pickers to be consecutive
for (ulong i = shiftAfter+1; i < (ulong)currentPick.LongLength; i++) {
currentPick[i] = currentPick[i-1] + 1;
}
}
} while (loop);
}
return allSubsets;
}
This solution worked for me:
private static void findSubsets(int array[])
{
int numOfSubsets = 1 << array.length;
for(int i = 0; i < numOfSubsets; i++)
{
int pos = array.length - 1;
int bitmask = i;
System.out.print("{");
while(bitmask > 0)
{
if((bitmask & 1) == 1)
System.out.print(array[pos]+",");
bitmask >>= 1;
pos--;
}
System.out.print("}");
}
}
Swift implementation:
Below are two variants on the answer provided by afsantos.
The first implementation of the combinations function mirrors the functionality of the original Java implementation.
The second implementation is a general case for finding all combinations of k values from the set [0, setSize). If this is really all you need, this implementation will be a bit more efficient.
In addition, they include a few minor optimizations and a smidgin logic simplification.
/// Calculate the binomial for a set with a subset size
func binomial(setSize: Int, subsetSize: Int) -> Int
{
if (subsetSize <= 0 || subsetSize > setSize) { return 0 }
// Take advantage of symmetry
var subsetSizeDelta = subsetSize
if (subsetSizeDelta > setSize - subsetSizeDelta)
{
subsetSizeDelta = setSize - subsetSizeDelta
}
// Early-out
if subsetSizeDelta == 0 { return 1 }
var c = 1
for i in 1...subsetSizeDelta
{
c = c * (setSize - (subsetSizeDelta - i))
c = c / i
}
return c
}
/// Calculates all possible combinations of subsets of `subsetSize` values within `set`
func combinations(subsetSize: Int, set: [Int]) -> [[Int]]?
{
// Validate inputs
if subsetSize <= 0 || subsetSize > set.count { return nil }
// Use a binomial to calculate total possible combinations
let comboCount = binomial(setSize: set.count, subsetSize: subsetSize)
if comboCount == 0 { return nil }
// Our set of combinations
var combos = [[Int]]()
combos.reserveCapacity(comboCount)
// Initialize the combination to the first group of set indices
var subsetIndices = [Int](0..<subsetSize)
// For every combination
for _ in 0..<comboCount
{
// Add the new combination
var comboArr = [Int]()
comboArr.reserveCapacity(subsetSize)
for j in subsetIndices { comboArr.append(set[j]) }
combos.append(comboArr)
// Update combination, starting with the last
var x = subsetSize - 1
while true
{
// Move to next
subsetIndices[x] = subsetIndices[x] + 1
// If crossing boundaries, move previous
if (subsetIndices[x] > set.count - (subsetSize - x))
{
x -= 1
if x >= 0 { continue }
}
else
{
for x1 in x+1..<subsetSize
{
subsetIndices[x1] = subsetIndices[x1 - 1] + 1
}
}
break
}
}
return combos
}
/// Calculates all possible combinations of subsets of `subsetSize` values within a set
/// of zero-based values for the set [0, `setSize`)
func combinations(subsetSize: Int, setSize: Int) -> [[Int]]?
{
// Validate inputs
if subsetSize <= 0 || subsetSize > setSize { return nil }
// Use a binomial to calculate total possible combinations
let comboCount = binomial(setSize: setSize, subsetSize: subsetSize)
if comboCount == 0 { return nil }
// Our set of combinations
var combos = [[Int]]()
combos.reserveCapacity(comboCount)
// Initialize the combination to the first group of elements
var subsetValues = [Int](0..<subsetSize)
// For every combination
for _ in 0..<comboCount
{
// Add the new combination
combos.append([Int](subsetValues))
// Update combination, starting with the last
var x = subsetSize - 1
while true
{
// Move to next
subsetValues[x] = subsetValues[x] + 1
// If crossing boundaries, move previous
if (subsetValues[x] > setSize - (subsetSize - x))
{
x -= 1
if x >= 0 { continue }
}
else
{
for x1 in x+1..<subsetSize
{
subsetValues[x1] = subsetValues[x1 - 1] + 1
}
}
break
}
}
return combos
}