我有这段代码以递归方式获取字符串中所有字符串的排列:
public static List<List<String>> combinations(List<String> strings)
{
if (strings.size() > 1)
{
List<List<String>> result = new ArrayList<List<String>>();
for (String str : strings)
{
List<String> subStrings = new ArrayList<String>(strings);
subStrings.remove(str);
result.add(new ArrayList<String>(Arrays.asList(str)));
for (List<String> combos : combinations(subStrings))
{
combos.add(str);
result.add(combos);
}
}
return result;
}
else
{
List<List<String>> result = new ArrayList<List<String>>();
result.add(new ArrayList<String>(strings));
return result;
}
}
如果我的arraylist包含太多值,它会溢出堆栈。我已经知道将算法从递归转换为迭代会帮助我解决这个内存问题,因为我会在堆上自己处理堆栈而不是使用本机堆栈。我以前从未这样做过,也无法解决如何解决这个问题。我的问题并不像看到这种转变的例子那么简单,所以我可以非常感谢有关如何实现这一目标的一些提示。
答案 0 :(得分:1)
如下所示,使用特殊的WorkPair类来模拟将在递归方法中创建的堆栈帧。通常,当转换为迭代方法时,您可能需要创建一个存储部分工作的数据结构,就像递归方法一样,此信息存储在堆栈中(我们没有)。
private static class WorkPair{
public final List<String> so_far;
public final List<String> left;
public WorkPair(List<String> sf,List<String> l){
so_far=sf;left=l;
}
}
public static List<List<String>> combinationsIterative(List<String> strings)
{
Queue<WorkPair> queue = new LinkedList<WorkPair>();
// setup queue
for(String str : strings){
List<String> so_far = new ArrayList<String>(Arrays.asList(str));
List<String> left = new ArrayList<String>(strings);
left.remove(str);
queue.add(new WorkPair(so_far,left));
}
// collect the results
List<List<String>> result = new ArrayList<List<String>>();
while(!queue.isEmpty()){
WorkPair pair = queue.remove();
// at each stage add the list so_far
List<String> so_far_add = new ArrayList<String>(pair.so_far);
result.add(so_far_add);
// if there's more work to be done create more workpairs
if(pair.left.size()>0){
// push work items for so_far + one element of left
for(String str : pair.left){
List<String> so_far = new ArrayList<String>(pair.so_far);
so_far.add(str);
List<String> left = new ArrayList<String>(pair.left);
left.remove(str);
queue.add(new WorkPair(so_far,left));
}
}
}
return result;
}
答案 1 :(得分:1)
你基本上需要的是迭代的powerset结构。查看this sample code (section 'Iterative')以了解如何使用Java完成集合任务。如果在组合原始字符串的给定子集时需要区分不同的顺序,则必须在第二个处理步骤中生成每个powerset元素的所有排列。 This page将帮助您开始实现它(使用代码为您提供索引1..<list_size>
的所有排列,添加一个简单的映射来获取有序的字符串列表。)
但是,请考虑您是否确实需要字符串集的显式表示。您可以等效地使用k
中的数字1..<original set size>
作为位向量,位#i
指示是否包含源列表中位置i
的字符串。在有序组合的情况下,排列将由k
及其1
位的数量唯一确定。
由于排列是可排序的,您实际上只需要2个数字+原始列表来唯一标识结果的每个元素,并轻松重建实际的字符串组合。
This SO question也可能对你感兴趣。