Get all 1-k tuples in a n-tuple

依然范特西╮ 提交于 2019-12-02 22:39:39

问题


With n=5 and k=3 the following loop will do it

List<String> l=new ArrayList<String>();
l.add("A");l.add("B");l.add("C");l.add("D");l.add("E");
int broadcastSize = (int) Math.pow(2, l.size());
for (int i = 1; i < broadcastSize; i++) {
    StringBuffer buffer = new StringBuffer(50);
    int mask = i;
    int j = 0;   
    int size=0;
    System.out.println();
    while (mask > 0) {
        if ((mask & 1) == 1) {
            System.out.println(".. "+mask);
            buffer.append(l.get(j));
            if (++size>3){
                buffer = new StringBuffer(50);
                break;
            }
        }
        System.out.println(" "+mask);
        mask >>= 1;
        j++;
    }
    if (buffer.length()>0)
        System.out.println(buffer.toString());

}

but it's not efficient I would like to do it with Banker's sequence and thus explore first singletons, then pairs, then 3-tuple and stop.

I did not find a way do that, but at least this loop should be more efficient:

List<String> l=new ArrayList<String>();
l.add("A");l.add("B");l.add("C");l.add("D");l.add("E");
int broadcastSize = (int) Math.pow(2, l.size());
for (int i = 1; i < broadcastSize; i++) {
    StringBuffer buffer = new StringBuffer(50);
    int mask = i;
    int j = 0;   

    if (StringUtils.countMatches(Integer.toBinaryString(i), "1") < 4){
        while (mask > 0) {
            if ((mask & 1) == 1) {
                buffer.append(l.get(j));

            }
            mask >>= 1;
            j++;
        }
        if (buffer.length()>0)
            System.out.println(buffer.toString());
    }


}

there is also: but k embedded loops looks ugly

//singleton
for (int i = 0; i < l.size(); i++) {
    System.out.println(l.get(i));
}

//pairs
for (int i = 0; i < l.size(); i++) {
    for (int j = i+1; j < l.size(); j++) {
        System.out.println(l.get(i)+l.get(j));
    }
}

//3-tuple
for (int i = 0; i < l.size(); i++) {
    for (int j = i+1; j < l.size(); j++) {
        for (int k = j+1; k < l.size(); k++) {
            System.out.println(l.get(i)+l.get(j)+l.get(k));
        }
    }
}
//...
// k-tuple

回答1:


This technique is called Gosper's hack. It only works for n <= 32 because it uses the bits of an int, but you can increase it to 64 if you use a long.

int nextCombo(int x) {
  // moves to the next combination with the same number of 1 bits
  int u = x & (-x);
  int v = u + x;
  return v + (((v ^ x) / u) >> 2);
}

...
for (int x = (1 << k) - 1; (x >>> n) == 0; x = nextCombo(x)) {
  System.out.println(Integer.toBinaryString(x));
}

For n = 5 and k = 3, this prints

111
1011
1101
1110
10011
10101
10110
11001
11010
11100

exactly as you'd expect.




回答2:


this should be the most efficient way, even if k embedded loops looks ugly

//singleton
for (int i = 0; i < l.size(); i++) {
    System.out.println(l.get(i));
}

//pairs
for (int i = 0; i < l.size(); i++) {
    for (int j = i+1; j < l.size(); j++) {
        System.out.println(l.get(i)+l.get(j));
    }
}

//3-tuple
for (int i = 0; i < l.size(); i++) {
    for (int j = i+1; j < l.size(); j++) {
        for (int k = j+1; k < l.size(); k++) {
            System.out.println(l.get(i)+l.get(j)+l.get(k));
        }
    }
}
// ...
//k-tuple



回答3:


Apache commons has iterators for subsets of size k, and for permutations. Here is an iterator that iterates through 1-k tuples of an n-tuple, that combines the two:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.collections4.iterators.PermutationIterator;
import org.apache.commons.math3.util.Combinations;

public class AllTuplesUpToKIterator implements Iterator<List<Integer>> {
    private Iterator<int[]> combinationIterator;
    private PermutationIterator<Integer> permutationIterator;
    int i;
    int k;
    int n;

    public AllTuplesUpToKIterator(int n, int k) {
        this.i = 1;
        this.k = k;
        this.n = n;
        combinationIterator = new Combinations(n, 1).iterator();
        permutationIterator = new PermutationIterator<Integer>(intArrayToIntegerList(combinationIterator.next()));
    }

    @Override
    public boolean hasNext() {
        if (permutationIterator.hasNext()) {
            return true;
        } else if (combinationIterator.hasNext()) {
            return true;
        } else if (i<k) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public List<Integer> next() {
        if (!permutationIterator.hasNext()) {
            if (!combinationIterator.hasNext()) {
                i++;
                combinationIterator = new Combinations(n, i).iterator();
            }
            permutationIterator = new PermutationIterator<Integer>(intArrayToIntegerList(combinationIterator.next()));          
        }
        return permutationIterator.next();
    }

    @Override
    public void remove() {
        // TODO Auto-generated method stub

    }

    public static List<Integer> intArrayToIntegerList(int[] arr) {
        List<Integer> result = new ArrayList<Integer>();
        for (int i=0; i< arr.length; i++) {
            result.add(arr[i]);
        }
        return result;
    }


    public static void main(String[] args) {
        int n = 4;
        int k = 2;
        for (AllTuplesUpToKIterator iter= new AllTuplesUpToKIterator(n, k); iter.hasNext();) {
            System.out.println(iter.next());
        }

    }
}


来源:https://stackoverflow.com/questions/10838666/get-all-1-k-tuples-in-a-n-tuple

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!