列出所有可能的组合

时间:2011-01-27 17:37:09

标签: java arrays algorithm

这就是我想要做的事情:

  

给出一个名单,打印出所有名称   三个名字的组合   一次。如果列表太少了   元素,不要打印任何东西。名称   必须以与他们相同的顺序发生   出现在列表中。所以,如果列表   包含肯尼迪,约翰逊,   尼克松,福特,你编程打印:

     

[肯尼迪,约翰逊,尼克松]
  [肯尼迪,约翰逊,福特]
  [肯尼迪,尼克松,福特]   [约翰逊,尼克松,福特]

     

将值放入数组中,然后使用   Arrays.toString()方法打印   结果,每行一个。

     

参数:list - - 名称列表。

现在我正在使用print语句来查看我是否在正确的轨道上,如果我是,我将完成将其调整为数组。

这是我的代码:

int x = 0;
 int y = 1; 
 int z = 2; 


 for(int i = 0; i<list.length;i++){

  for (int j = 0;j<3;j++){

   System.out.print(list[x]);
   System.out.print(list[y]);
   System.out.print(list[z]);

   if (j>=1){y++;}
   if (z != list.length){z++;}

  }
  x++; 

 }

这是我得到的错误:

Enter commands:
trio Kennedy, Johnson, Nixon,ford
Kennedyjava.lang.ArrayIndexOutOfBoundsException: 1
 at MyAssign1.trio(MyAssign1.java:204)
 at Assign1.processOneCommand(Assign1.java:109)
 at CmdInterpreter.processCommands(CmdInterpreter.java:198)
 at CmdInterpreter.processCommands(CmdInterpreter.java:230)
 at CmdInterpreter.ooMain(CmdInterpreter.java:243)
 at MyAssign1.main(MyAssign1.java:20)

第204行是:

System.out.print(list[y]);

我做错了什么?

6 个答案:

答案 0 :(得分:5)

正如您对问题的评论所示,发生ArrayIndexOutOfBoundsException异常是因为您正在访问超出数组list限制的索引。看看:

if (j>=1){y++;}

y的值总是在增加。在list.length次迭代之后,异常肯定会引发异常。异常的解决方案很简单:不要访问索引超出其范围的数组。

虽然存在许多组合问题的解决方案,但让您回到正轨的最简单方法是:

for (int a = 0; a < list.length; a++) {
    for (int b = a + 1; b < list.length; b++) {
        for (int c = b + 1; c < list.length; c++) {
            System.out.print(list[a] + ", ");
            System.out.print(list[b] + ", ");
            System.out.println(list[c]);
        }
    }
}

答案 1 :(得分:3)

看着你的代码(而且我不希望自己是不友好的),我认为你没有与这个代码走在正确的轨道上。

我建议您作为第一步完全忘记代码,并简单地考虑您使用的算法或流程。您应该能够将以英语写下来作为步骤列表。只有拥有该列表后,您是否应该考虑如何在代码中实现它。

要回答您的实际问题,您目前正在获取异常,因为您正在访问列表末尾的元素。部分原因是,z 等于 list.length之前的增量停止太晚;长度为4的数组具有索引为0-3的元素,因此list[4]将抛出您遇到的异常。

(现在你的组合查找逻辑不会做正确的事。x永远不会改变,因此每个组合(给出示例)都将以Kennedy开头。作为{{1}命中它停止增长的列表的长度,但z继续增长,所以你会得到一些迭代,其中第二和第三个条目是相同的,你没有考虑y是否会超过界限。你也在循环y但没有做任何事情。你的程序,如果没有崩溃,会输出这样的东西:

i

你有一个很多的特殊套管。假设您需要在Kennedy, Johnson, Nixon Kennedy, Johnson, Ford Kennedy, Nixon, Ford Kennedy, Ford, Ford Kennedy, Johnson, Nixon Kennedy, Johnson, Ford Kennedy, Nixon, Ford Kennedy, Ford, Ford Kennedy, Johnson, Nixon Kennedy, Johnson, Ford Kennedy, Nixon, Ford Kennedy, Ford, Ford Kennedy, Johnson, Nixon Kennedy, Johnson, Ford Kennedy, Nixon, Ford Kennedy, Ford, Ford 时进行迭代,只有在输入中恰好有四个元素时才有效。您应该增加j < 3 y的检查再次是一个特殊情况,仅使用四个元素创建正确的结果。同样,我鼓励您考虑一下您可能用来查找任意长度的三个元素的每个元素的过程,而不考虑代码。)

答案 2 :(得分:0)

我假设您正在使用它来包装您的代码:http://www.cs.colostate.edu/~cs161/assignments/PA1/src/CmdInterpreter.java

我认为你的主要问题可能就是你执行命令的方式。在我看来它只是认为肯尼迪是阵列的一部分,而不是其他名称。请尝试使用此命令:

trio Kennedy,Johnson,Nixon,Ford

将空格留出可能有助于解析器解释数组。

答案 3 :(得分:0)

我认为您的问题不在您发布的代码中,而是在您未向我们展示的代码中。你是如何创建和填充list数组的?看起来列表初始化错误,实际上只包含一个元素。

尝试在代码中添加类似内容以进行检查:

// Check size of list array.
System.out.println("list.length=" + list.length);

// Print out contents of list array.
for(int i=0; i<list.length; i++) {
   System.out.println(i + "=" + list[i]);
}

答案 4 :(得分:0)

尝试与我的解决方案进行比较,逻辑不那么复杂:

import java.util.ArrayList;
import java.util.Arrays;

public class PrintCombinations
{
    private final static int LEN = 3;

    //for example: args = [Kennedy, Johnson, Nixon, Ford]
    public static void main(String[] args)
    {
        if (args.length < LEN)
            return; //too few data

        //collect combinations
        String[][] combinations = collectCombinations(args);

        //print result, one per line
        for(String[] comb : combinations)
        {
            System.out.println(Arrays.toString(comb));
        }
    }

    //collects all combinations and returns the result array 
    private static String[][] collectCombinations(String[] list)
    {
        int n = list.length;

        java.util.ArrayList<String[]> combinations = new ArrayList<String[]>();

        //the last possible 'i' is list[n-LEN], so no need go further
        for(int i = 0; i <= n - LEN; ++i)
        {
            //the last possible 'j' is list[n-(LEN-1)]
            for(int j = i+1; j <= n - (LEN-1); ++j)
            {
                //the last possible 'k' is list[n-(LEN-2)]
                //n-(LEN-2)==n-(3-2)==n-1, its the last element in the list
                for(int k = j+1; k <= n - (LEN-2); ++k)
                {
                    combinations.add(new String[] {
                            list[i],
                            list[j],
                            list[k]});  
                }               
            }
        }
        return combinations.toArray(new String[0][]);
    }
}

我已经包含了一些范围优化,以避免在循环内进行不必要的运行。 你不能简单地改变LEN来修改序列长度,它只是为了从代码中消除“幻数”3。

备注:如果你想要更长的序列而不是3,你需要嵌入一个新的循环深度。

希望它有所帮助!

答案 5 :(得分:0)

下面的方法将任意数量的字符串作为输入列表。并将生成可能的排列/组合数量。在Permutations的情况下,您还可以提及是否需要重复String。请注意,如果ComboOnly为true,则isRepeat不起作用。

private static void generatePerms(List<String> list, boolean isRepeat, boolean comboOnly) {     
    int n = list.size();
    List<List<Integer>> lists = new ArrayList<List<Integer>>();

     for (int i = 0; i< n;i++) {
         int j = (comboOnly?i+1:0);
         for ( ; j < n;j++) {
             if (!isRepeat && i == j) continue;
             int k = (comboOnly?j+1:0);
             for (; k< n ;k++) {
                 if ( !isRepeat && (k ==i || k ==j)) continue;
                 System.out.println(list.get(i),list.get(j),list.get(k)));
             }
         }
     }

    return lists;
}