从元素列表中创建固定大小的非重复排列列表

时间:2017-07-06 13:30:25

标签: java permutation

我有一个对象列表M := [A, B, C, ... Z],我想创建一个新列表N,其中包含这些对象的非重复固定大小“f”排列。

所以N应为(for f = 2) [[A, B], [A, C], ...],但不应包含[A, A]等重复,如果[A, B]设置为[B, A]则应忽略。

我找到了类似GuavasPowerSet”的内容,但这不会帮助我,因为它无法“裁剪”到固定大小。

我希望我已正确陈述我的问题。

f应始终为2

基于http://algorithms.tutorialhorizon.com/print-all-combinations-of-subset-of-size-k-from-given-array/我已完成以下操作:

private Set<List<Object>> combineObjects(List<Object> M) {
    boolean[] used = new boolean[M.size()];
    return generateObjectCombinations(M, 0, 0, used);
}

private Set<List<Object>> generateObjectCombinations(
    List<Object> M,
    int start,
    int curLen,
    boolean[] used
) {
    Set<List<Object>> returnSet = new HashSet<>();
    if (curLen == 2) {
        List<Object> data = newArrayList();
        for (int i = 0; i < M.size(); i++) {
            if (used[i]) {
                data.add(M.get(i));
            }
        }
        returnSet.add(data);
        return returnSet;
    }
    if (start == M.size()) {
        return Collections.emptySet();
    }
    used[start] = true;
    returnSet.addAll(generateObjectCombinations(M, start + 1, curLen + 1, used));
    used[start] = false;
    returnSet.addAll(generateObjectCombinations(M, start + 1, curLen, used));
    return returnSet;
}

它正在运作,但我想知道是否有“更清洁”的解决方案。我想消除bool-array。

不,这不是我的功课。也许我只是累了,应该休假。

修改 根据@ azro的回答,我重新构建了这样的代码:

List<List<Object>> combinations = new ArrayList<>();
List<Object> M = new ArrayList<>();

for (int i = 0; i < M.size(); i++) {
    Object outerM = M.get(i);

    for (int j = i; j < M.size(); j++) {
        Object innerM = M.get(j);
        if (innerM.equals(outerM)) {
            continue;
        }
        combinations.add(Lists.newArrayList(outerM, innerM));
    }
}

甚至更好

List<List<Object>> combinations = new ArrayList<>();
List<Object> M = new ArrayList<>();

for (int i = 0; i < M.size(); i++) {
    Object outerM = M.get(i);

    for (int j = (i + 1); j < M.size(); j++) {
        Object innerM = M.get(j);
        combinations.add(Lists.newArrayList(outerM, innerM));
    }
}

我真应该度过一个假期。谢谢@azro !!

2 个答案:

答案 0 :(得分:1)

由于你没有写“f应该总是2”作为开头我写了一个适用于f>=1的解决方案,所以这里是方法以及如何使用它:

public static void main(String[] args) {
        List<String> letter = Arrays.asList("A", "B", "C", "D", "E");
        List<String> res = new ArrayList<>();
        res.addAll(letter);
        int size = 2;

        for (int i = 1; i < size ; i++) {
            res = addLetter(res, letter);   //add a letter to all
        }

        res.forEach(p -> System.out.println(p));
}

public static List<String> addLetter(List<String> already, List<String> letters) {
    List<String> res = new ArrayList<>();

    for (String al : already) {
        for (String let : letters) {
            if (!al.contains(let)) {
                res.add(al + let);
            }
        }
    }
    return res;
}

如果“f应该始终为2”,则只需要:

public static void main(String[] args) {
    List<String> letters = Arrays.asList("A", "B", "C", "D", "E");
    List<String> res = new ArrayList<>();

    for (String al : letters) {
        for (String let : letters) {
            if (!al.contains(let)) {
                res.add(al + let);
            }
        }
    }
    res.forEach(p -> System.out.println(p));
}

答案 1 :(得分:0)

我不确定这是否是最好的解决方案,但是你在这里:

btn.setBackgroundResource(android.R.drawable.btn_default)

用法:

static HashSet<HashSet<String>> getCombinations(HashSet<HashSet<String>> s, int f)
{
    if(f == 1)
        return s;
    HashSet<HashSet<String>> newSet = new HashSet<HashSet<String>>();
    for (HashSet<String> ss : s)
    {
        for(String elm : A)
        {
            if(ss.contains(elm))
                continue;
            HashSet<String> sss = (HashSet<String>)ss.clone();
            sss.add(elm);
            newSet.add(sss);
        }
    }
    return getCombinations(newSet, f-1);
}