当前位置: 首页 > 面试题库 >

如何在Java中根据大小为n的集合迭代生成k个元素子集?

耿建弼
2023-03-14
问题内容

我正在研究一个难题,其中涉及分析所有大小的k个子集,并找出哪个子集是最佳的。我写了一个解决方案,当子集的数量很少时可以使用,但是对于较大的问题,它用尽了内存。现在,我正在尝试将用python编写的迭代函数转换为java,以便我可以在创建每个子集时对其进行分析,并仅获取代表其优化程度的值,而不是整个集的值,以便不会耗尽记忆。这是我到目前为止的内容,即使很小的问题也似乎还没有解决:

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;

}

有人可以帮我调试此功能或建议另一种算法来迭代生成大小为k的子集吗?

编辑:我终于使该函数正常工作,我不得不创建一个与i相同的新变量来进行i和脱粒比较,因为python处理循环索引的方式不同。


问题答案:

首先,如果您打算对列表进行随机访问,则应选择一个可以有效支持列表的列表实现。从LinkedList上的javadoc:

所有操作均按双向链表的预期执行。索引到列表中的操作将从开头或结尾遍历列表,以更接近指定索引的位置为准。

ArrayList不仅空间效率更高,而且随机访问速度更快。实际上,由于您事先知道了长度,因此甚至可以使用普通数组。

算法:让我们从简单开始:如何生成大小为1的所有子集?大概是这样的:

for (int i = 0; i < set.length; i++) {
    int[] subset = {i};
    process(subset);
}

其中process是一种对集合进行某些操作的方法,例如检查它是否比到目前为止处理的所有子集“更好”。

现在,您将如何扩展它以适用于大小为2的子集?大小为2的子集和大小为1的子集之间有什么关系?嗯,任何大小为2的子集都可以通过删除其最大元素而变成大小为1的子集。换句话说,可以通过采用大小为1的子集并添加比集合中所有其他元素大的新元素来生成大小为2的每个子集。在代码中:

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);
    }
}

对于任意大小的k的子集,请注意,可以通过切碎最大元素将大小为k的任何子集转换为大小为k-1的子集。也就是说,可以通过生成大小为k-1的所有子集来生成大小为k的所有子集,对于每个子集,以及每个大于子集中最大值的值,都将该值添加到集合中。在代码中:

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);
        }
    }
}

测试代码:

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);
}

但是在对大型集合进行调用之前,请记住,子集的数量可能会快速增长。



 类似资料:
  • 问题内容: 我有一组值,并想创建包含2个元素的所有子集的列表。 例如,源集具有以下2个元素的子集: 有没有办法在python中做到这一点? 问题答案: 好像你想要的: 如果要设置,则必须显式转换它们。如果您不介意使用迭代器而不是列表,并且使用的是Python 3,则可以使用: 要一次查看所有结果,可以将的输出传递给。(在Python 2中,的输出自动为列表。) 但是,如果您知道需要列表,则列表理解

  • 这是一个算法问题。如果我错过了Python中任何有帮助的现有函数,请大喊一声。 给定一组元素的,我们可以在Python中使用函数来找到所有唯一的k元素子集。让我们调用包含所有这些子集的集合。请注意,每个这样的子集都有不同的元素。 问题是两步走。首先,给定这些k-不同元素子集,我想组合(其中的一些),这样(组合只是一些子集的超集): > 构图中任意两个子集之间的交集为空 构图中所有子集的并集给出的正

  • 我有一个名为计算的方法,它需要太长时间才能完成。所以我决定将我的信息列表对象部分发送到这个方法。我如何遍历每n个元素?

  • 有没有一种方法我可以用某种方式迭代光标我可以暂停它,然后再继续?MongodbCursor保存最后访问的项目?我只知道foreach迭代,但是否有一些像这样的迭代? 如果有类似的东西存在,我可以保存查询的最后一个项目。提前致谢

  • 问题内容: AFAIK有两种方法: 遍历集合的副本 使用实际集合的迭代器 例如, 和 是否有任何理由偏爱一种方法(例如,出于可读性的简单原因而偏爱第一种方法)? 问题答案: 让我举几个例子,并提出一些避免方案。 假设我们有以下藏书 收集并删除 第一种技术是收集所有要删除的对象(例如,使用增强的for循环),并在完成迭代后删除所有找到的对象。 假设你要执行的操作是“删除”。 如果要“添加”此方法也可

  • AFAIK,有两种方法: 迭代集合的副本 使用实际集合的迭代器 例如, 而且 有没有理由偏爱一种方法而不是另一种方法(例如,由于可读性的简单原因而偏爱第一种方法)?