如何使这种组合/排列方法递归?

Posted

技术标签:

【中文标题】如何使这种组合/排列方法递归?【英文标题】:How do I make this combinations/permutations method recursive? 【发布时间】:2013-01-07 04:08:11 【问题描述】:

我有一个字符串数组列表,希望将所有可能的组合存储到另一个集合中。

例如:

[air,bus,car]
->
[air]
[bus]
[car]
[air,bus]
[air,car]
[bus,air]
[bus,car]
[car,air]
[car,bus]
[air,bus,car]
[air,car,bus]
...
[car,bus,air]

重复并不重要。我现在的代码是:

public ArrayList<String> comb(ArrayList<String> wrds, ArrayList<String> str, int size)

    ArrayList<String> s = new ArrayList<String>();
    s.addAll(str);
    if(size != a1.size())
    
        Iterator e = a1.iterator();
        while(e.hasNext())
        
            s.add((String)e.next());
        
        size++;
    

我试图让它递归调用自己,以便它可以存储组合。我可以就我的代码中缺少的位置或部分获得任何帮助吗?

【问题讨论】:

如果这是家庭作业,请标记它。 a1 来自哪里? 假设这是家庭作业。变量 a1 是 [air,bus,car] 的数组列表。 您缺少递归调用本身。 是的,这就是我寻求帮助的原因。我被难住了。 我认为 homework 标签已被弃用。 【参考方案1】:

鉴于这是作业,我将尝试为您提供答案的背景。

解决这个问题的关键是使用递归。

首先假设您的数组中有两个项目。你可以删除第一个项目给你你的第一个组合。将剩余的项目添加到第一个项目为您提供第二个组合。删除第二个项目会给你第三个组合。添加剩余项目为您提供第四种组合。如果你有["air", "bus"],它会是这样的:

["air"]
["air", "bus"]
["bus"]
["bus", "air"]

返回的方法可能如下所示:

String[][] combinations(String[] strings)

需要注意的重要事项是可以将包含单个字符串的数组传递给此方法,并且它可以返回一个包含包含单个字符串的数组的数组。

这个问题有点复杂,因为你必须对字符串组合进行计数,所以在我们解决这个问题之前,了解递归很重要。

假设您想编写一个乘法方法,它接受两个数字并将它们相乘,但您只能使用加法和减法。您可以编写一个递归函数,将其中一个数字添加到自身,直到另一个数字达到退出条件,例如:

public int multiply(int value1, int value2) 

  if (value1 > 1) 
  
    int remaining = value1 - 1;
    return value2 + multiply(remaining, value2);
  
  else 
  
    return value2;
  

你可以对数组做同样的事情,只是当a值命中1时退出你在数组包含一个项目时退出,比如:

public String[][] combinations(String[] strings) 

  if (strings.length > 1) 
  
    ...
  
  else 
  
    return new String[][]strings;
  

由于 Java API 的原因,使用 java.util.List 比使用数组更容易,因此您需要以下内容:

public List<List<String>> combinations(List<String> strings) 

  if (strings.size()> 1) 
  
    ...
  
  else 
  
    List<List<String>> result = new ArrayList<List<String>>();
    result.add(strings);
    return result;
  

现在,... 才是最重要的。您需要保留一个列表列表作为结果并遍历strings。对于每个字符串,您可以将该字符串添加到结果中,然后您需要创建一个减去当前字符串的子列表,您可以使用该子列表再次调用combinations 方法,再次遍历结果,添加当前字符串每个列表它包含了。在代码中它看起来像:

public 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> combinations : combinations(subStrings)) 
      
        combinations.add(str);
        result.add(combinations);
      
    

    return result;
  
  else 
  
    List<List<String>> result = new ArrayList<List<String>>();
    result.add(new ArrayList<String>(strings));
    return result;
  

总之,您所做的是将字符串列表缩减为单个项目,然后将其与前面的项目组合以在线程返回调用堆栈时生成所有可能的组合。

【讨论】:

你的解释很清楚。非常感谢!我觉得我需要一个列表的列表,但不知道我将如何使用它。回到递归,我开始更好地理解它。我很感激,尼克! 不客气,尽管没有什么比投票和接受答案更能表达感谢的了。 很抱歉。虽然我不能投票,因为我没有超过 15 个,但我接受了答案。谢谢提醒。 正是我想要的。很好的答案尼克【参考方案2】:
public static void combination(Object[] array)
         for(int x = 0; x < (1 << array.length); x++)
             System.out.print("[");
             for(int y = 0; y < array.length; y++)
                 if(checkIsOn(x, y)
                    System.out.print(array[y]);
                 
             
             System.out.println("]");
         
    

    public static boolean checkIsOn(int mast, int position)
         return (mast & (1 << position) > 0);
    

【讨论】:

这似乎输出了一个超集。但我不明白这是如何工作的。你/有人能把它分解一下吗?【参考方案3】:

使用列表作为递归函数的参数。您可以使用包含除第一项之外的所有内容的新列表从其内部调用该函数。

【讨论】:

但我仍然不确定如何将它们中的每一个添加到 arraylist 或者甚至是 arraylist 的数组中。

以上是关于如何使这种组合/排列方法递归?的主要内容,如果未能解决你的问题,请参考以下文章

具有多个列表的递归排列

5972: 递归入门全排列

递归:排列

递归实现组合型指数型排列型 枚举

POJ1644状态转移的思想——排列组合

算法学习——递归和排列组合