找到组合,给出n个带有x个球的盒子

时间:2014-02-23 17:49:30

标签: java algorithm list map combinations

我正在开展一个项目,其中我有三个盒子(截至目前),每个盒子都有一些颜色的球

所以我将它们存储在Map of String and List of String中,如下所示。

Map<String, List<String>> boxBallMap = new LinkedHashMap<String, List<String>>();

上面地图中的数据可以是这样的 -

{box1=[blue, red, orange]}
{box2=[blue, red]}
{box3=[blue, red, orange]}

因此,盒子中球的可能组合可以是 -

(POINT A) ::所有具有相同球数的盒子 -

{box1=[blue, red, orange]}
{box2=[blue, red, orange]}
{box3=[blue, red, orange]}

or

(POINT B) ::任何一个盒子都没有球。所以让我们说box3没有任何球 -

{box1=[blue, red, orange]}
{box2=[blue, red, orange]}
{box3=[]}

or

(POINT C) ::有些盒子的球数较少。所以让我们说box2只有两个球 -

{box1=[blue, red, orange]}
{box2=[blue, red]}
{box3=[blue, red, orange]}

or

(POINT D) ::任何一个盒子都没有球。所以让我们说box3和box2没有任何球 -

{box1=[blue, red, orange]}
{box2=[]}
{box3=[]}

ProblemStatement: -

基于上面的输入,我需要返回一个List<Map<String, String>>的映射,假设对于(POINT A),下面的映射将作为输出返回 -

[{box1=blue, box2=red, box3=orange}, 
{box1=red, box2=orange, box3=blue}, 
{box1=orange, box2=blue, box3=red}]

如果你看到,每一行的每一行都有替代颜色的球 - 意思是blue for box1red for box2orange for box3。我不能在每一排都有相同颜色的球。所以这种组合是不可能的,因为它有两个盒子的相同颜色的球。

{box1=blue, box2=blue, box3=orange}

而且,在第二行中,我不会使用那个盒子的第一行中使用的那些球。

输出组合是根据传递的输入生成的,如(POINT A)所示。

现在,让我们说(POINT B)作为box3没有任何球的输入,我将返回另一个映射,如下所示{{ 1}}以及 -

List<Map<String, String>>

在上面的输出中,您可以看到没有[{box1=blue, box2=red}, {box1=red, box2=orange}, {box1=orange, box2=blue}] ,因为没有输入,但每行的box1和box2都有球的替代颜色。

现在,让我们说(POINT C)作为box3只有两种颜色的球的输入,我将返回另一个映射,如下所示{{ 1}}以及 -

box2

在上面的输出中,您可以在第二行看到没有List<Map<String, String>>,因为[{box1=blue, box2=red, box3=orange}, {box1=red, box3=blue}, {box1=orange, box2=blue, box3=red}] 只有box2box2颜色的球并且可以组合右边,box2在第一行和第三行,只是为了维持每一行都有交替颜色的球的规则。

现在我无法理解如何编写这样的方法,它可以返回我传递给这个问题的输入的映射基础?

注意: -

这里的盒子现在总是三个,但球可以如输入

中所示变化

任何建议对此都有很大帮助。感谢。

更新: -

我的基本问题是给出了如上所示的球和盒的输入 - 我将如何返回映射,使得在每一行中,盒子使用交替/不同颜色的球并且他们需要确保在之前的一排,那些球的颜色没有被同一个盒子使用过。

对于(POINT C)作为red只有两种颜色的球的输入,我想返回如下所示的映射,bluebox2好吧 -

List<Map<String, String>>
  • 在第一行中,[{box1=blue, box2=red, box3=orange}, {box1=red, box3=blue}, {box1=orange, box2=blue, box3=red}] box1 has bluebox2 has red具有交替颜色的球。
  • 在第二行,box3 has orange为什么? bcoz box1 has red已经在box1的第一行中使用,box3在第二行中没有blue
  • 同样适用于第三行。

我之前遇到的解决方案,但这假设每个方框中的球数总是相同的 -

box2

如果我们可以修改它以开始接受我的输入作为Map并在球的数量可以不同时处理用例,那么它对我来说将变得非常容易

更新

如果我尝试使用下面的输入组合,那么我输出为空,这是错误的。

public List<Map<String, String>> createMappings(List<String> boxes, List<String> balls) {
    List<Map<String, String>> result = new ArrayList<Map<String, String>>();
    for(int i = 0; i < balls.size(); i++) {
        Map<String, String> row = new HashMap<String,String>();
        for(int j = 0; j < boxes.size(); j++) {
            String box = boxes.get(j);
            int ballIndex = (j + i) % balls.size();
            String ball = balls.get(ballIndex);
            row.put(box, ball);
        }
        result.add(row);
    }
    return result;
}

但输出结果应如下所示 -

List<String> balls1 = Arrays.asList();
List<String> balls2 = Arrays.asList();
List<String> balls3 = Arrays.asList("red", "blue");


Map<String, List<String>> maps = new LinkedHashMap<String, List<String>>();
maps.put("box3", balls3);
maps.put("box2", balls2);
maps.put("box1", balls1);

List<Map<String, String>> mappings = generateMappings(maps);

// below mappings is coming as empty somehow which is wrong
System.out.println(mappings);

而且,它也不适用于以下输入 -

[{box3=red}, {box3=blue}]

使用上面的输入组合,我可以看到其他行中的相同颜色的球对于某些违反第三规则的盒子。

更新: -

我的规则是 -

  • 在每一行中,方框应具有交替的球颜色。如果您看到上面的内容,则每一行的每一行都有替代颜色的球 - 即第一行中的List<String> balls1 = Arrays.asList("red", "blue", "orange"); List<String> balls2 = Arrays.asList("red", "blue", "orange"); List<String> balls3 = Arrays.asList("red", "blue", "orange", "purple", "pink"); blue for box1red for box2
  • 其次,我不能在每一行中使用相同颜色的球。因此,下面的组合是不可能的,因为它对于一行中的两个盒子具有相同颜色的球。 orange for box3
  • 第三,在下一行中,我不会将这些球用于先前行中使用的盒子。因此,{box1=blue, box2=blue, box3=orange}的第二行不能blue,因为box1已在第一行中使用了box1

最终代码: -

最后的代码应该是这样的 -

public static List<Map<String, String>> create(Map<String, List<String>> input) {
List<Map<String, String>> output = new ArrayList<Map<String, String>>();
// find all boxes
List<String> boxes = new ArrayList<String>(input.keySet());

// find all colors
Set<String> distinctColors = new LinkedHashSet<String>();
for (List<String> e : input.values()) {
    for (String color : e) {
    if (!distinctColors.contains(color)) {
        distinctColors.add(color);
    }
    }
}
List<String> colors = new ArrayList<String>(distinctColors);

Set<String> generationHistory = new LinkedHashSet<String>();
int colorIndex = 0;
for(int i = 0; i < colors.size(); i++) {
    Map<String, String> row = new LinkedHashMap<String, String>();
    output.add(row);
    colorIndex = i;
    for(int j = 0; j < colors.size(); j++) {
    int boxIndex = j;
    if(boxIndex >= boxes.size()) {
        boxIndex = 0;
    }
    String box = boxes.get(boxIndex);
    List<String> boxColors = input.get(box);
    if(colorIndex >= colors.size()) {
        colorIndex = 0;
    }
    String color = colors.get(colorIndex++);
    // a combination is generated only if the actual
    // colors does exist in the actual box 
    // and it has not already been generated i all previous rows
    if(boxColors.contains(color) && isNotYetGenerated(box, color, generationHistory)) {
        row.put(box, color);
    }
    }
}

return output;
}

private static boolean isNotYetGenerated(String box, String color, Set<String> generationHistory) {
String key = box + "=" + color;
boolean notYetGenerated = !generationHistory.contains(key);
if (notYetGenerated) {
    generationHistory.add(key);
}
return notYetGenerated;
}

3 个答案:

答案 0 :(得分:2)

基本上你必须将所有盒子与所有可能的颜色组合在一起。在每个新行中,一个框获得分配给它在上一行中的下一个颜色。如果你编写所有可能的盒子/颜色组合并写下所有索引,它会变得更清晰。 PointA 是一个很好的例子:

输入

{box1=[blue, red, orange]}
{box2=[blue, red, orange]}
{box3=[blue, red, orange]}

以上输入的所有组合都是(前面有 boxIndex,colorIndex ):

0,0 {box1=blue}
0,1 {box1=red}
0,2 {box1=orange}

1,0 {box2=blue}
1,1 {box2=red}
1,2 {box2=orange}

2,0 {box3=blue}
2,1 {box3=red}
2,2 {box3=orange}

您正在寻找以下输出:

{box1=blue, box2=red, box3=orange}
{box1=red, box2=orange, box3=blue}
{box1=orange, box2=blue, box3=red}

因此,您正在寻找的指数如下:

row1    0,0     1,1     2,2
row2    0,1     1,2     2,0
row3    0,2     1,0     2,1

现在,当你知道自己在寻找什么时,就可以轻松编写一些循环(免责声明:据我正确理解你的问题/未完全测试!!! ):

public List<Map<String, String>> create(Map<String, List<String>> input) {
    List<Map<String, String>> output = new ArrayList<>();
    // find all boxes
    List<String> boxes = new ArrayList<>(input.keySet());

    // find all colors
    Set<String> distinctColors = new LinkedHashSet<>();
    for(List<String> e : input.values()) {
        for(String color : e) {
            if(! distinctColors.contains(color)) {
                distinctColors.add(color);  
            }
        }
    }
    List<String> colors = new ArrayList<String>(distinctColors);

    int colorIndex = 0;
    for(int i = 0; i < boxes.size(); i++) {
        Map<String, String> row = new LinkedHashMap<>();
        output.add(row);
        colorIndex = i;
        for(int j = 0; j < colors.size(); j++) {
            int boxIndex = j;
            if(boxIndex >= boxes.size()) {
                boxIndex = 0;
            }
            String box = boxes.get(boxIndex);
            List<String> boxColors = input.get(box);
            if(colorIndex >= colors.size()) {
                colorIndex = 0;
            }
            String color = colors.get(colorIndex++);
            // a combination is generated only if the actual
            // colors does exist in the actual box
            if(boxColors.contains(color)) {
                row.put(box, color);    
            }
        }
    }

    return output;
}

以下是使用您提供的一些输入的一些测试:

<强>点A

@Test
public void createFromPointA() {
    //    {box1=[blue, red, orange]}
    //    {box2=[blue, red, orange]}
    //    {box3=[blue, red, orange]}

    //    [{box1=blue, box2=red, box3=orange}, 
    //     {box1=red, box2=orange, box3=blue}, 
    //     {box1=orange, box2=blue, box3=red}]

    //    0,0 {box1=blue}
    //    0,1 {box1=red}
    //    0,2 {box1=orange}

    //    1,0 {box2=blue}
    //    1,1 {box2=red}
    //    1,2 {box2=orange}

    //    2,0 {box3=blue}
    //    2,1 {box3=red}
    //    2,2 {box3=orange}

    //    0,0   1,1     2,2
    //    0,1   1,2     2,0
    //    0,2   1,0     2,1

    Map<String, List<String>> input = new LinkedHashMap<>();
    input.put("box1", Arrays.asList("blue", "red", "orange"));
    input.put("box2", Arrays.asList("blue", "red", "orange"));
    input.put("box3", Arrays.asList("blue", "red", "orange"));

    List<Map<String, String>> output = create(input);
    for(Map<String, String> e : output) {
        System.out.println(e);  
    }
}

<强> PointB

@Test
public void createFromPointB() {
    //      {box1=[blue, red, orange]}
    //      {box2=[blue, red, orange]}
    //      {box3=[]}

    //      [{box1=blue, box2=red}, 
    //       {box1=red, box2=orange}, 
    //       {box1=orange, box2=blue}]

    //      0,0 {box1=blue}
    //      0,1 {box1=red}
    //      0,2 {box1=orange}

    //      1,0 {box2=blue}
    //      1,1 {box2=red}
    //      1,2 {box2=orange}

    //      2,x {box3=blue}
    //      2,x {box3=red}
    //      2,X {box3=orange}

    //      0,0     1,1     2,x
    //      0,1     1,1     2,x
    //      0,2     1,0     2,x

    Map<String, List<String>> input = new LinkedHashMap<>();
    input.put("box1", Arrays.asList("blue", "red", "orange"));
    input.put("box2", Arrays.asList("blue", "red", "orange"));
    input.put("box3", Collections.<String>emptyList());

    List<Map<String, String>> output = create(input);
    for(Map<String, String> e : output) {
        System.out.println(e);  
    }
}

<强> PointC

@Test
public void createFromPointC() {
    //      {box1=[blue, red, orange]}
    //      {box2=[blue, red]}
    //      {box3=[blue, red, orange]}

    //      [{box1=blue, box2=red, box3=orange}, 
    //       {box1=red, box3=blue}, 
    //       {box1=orange, box2=blue, box3=red}]

    //      0,0 {box1=blue}
    //      0,1 {box1=red}
    //      0,2 {box1=orange}

    //      1,0 {box2=blue}
    //      1,1 {box2=red}
    //      1,x {box2=orange}

    //      2,0 {box3=blue}
    //      2,1 {box3=red}
    //      2,2 {box3=orange}

    //      0,0     1,1     2,2
    //      0,1     1,x     2,0
    //      0,2     1,0     2,1

    Map<String, List<String>> input = new LinkedHashMap<>();
    input.put("box1", Arrays.asList("blue", "red", "orange"));
    input.put("box2", Arrays.asList("blue", "red"));
    input.put("box3", Arrays.asList("blue", "red", "orange"));

    List<Map<String, String>> output = create(input);
    for(Map<String, String> e : output) {
        System.out.println(e);  
    }
}

<强> OUTPUTA

{box1=blue, box2=red, box3=orange}
{box1=red, box2=orange, box3=blue}
{box1=orange, box2=blue, box3=red}

<强> OUTPUTB

{box1=blue, box2=red}
{box1=red, box2=orange}
{box1=orange, box2=blue}

<强> OutputC

{box1=blue, box2=red, box3=orange}
{box1=red, box3=blue}
{box1=orange, box2=blue, box3=red}

希望这有助于或至少为您找到解决方案提供一些提示。

修改

您可以替换外部for循环

for(int i = 0; i < boxes.size(); i++) {

for(int i = 0; i < colors.size(); i++) {

这样,生成的方向是在颜色数量不是方框的颜色数量之后。如果这对其他组合没有帮助,那么您可能需要在向行添加组合之前添加检查:

if(boxColors.contains(color) && notYetGenerated()) {
    row.put(box, color);    
}

编辑2

以下是isNotYetGenerated

的示例实现
private boolean isNotYetGenerated(String box, String color, 
                                  Set<String> generationHistory) {
    String key = box + "=" + color;
    boolean notYetGenerated = ! generationHistory.contains(key);
    if(notYetGenerated) {
        generationHistory.add(key);
    }
    return notYetGenerated;
}

create方法中创建一个集合并将其传递给该方法。

    Set<String> generationHistory = new LinkedHashSet<>();
    int colorIndex = 0;
    int index = boxes.size() > colors.size() ?  boxes.size() : colors.size();
    for(int i = 0; i < index; i++) {
        Map<String, String> row = new LinkedHashMap<>();
        output.add(row);
        colorIndex = i;
        for(int j = 0; j < index; j++) {
            int boxIndex = j;
            if(boxIndex >= boxes.size()) {
                boxIndex = 0;
            }
            String box = boxes.get(boxIndex);
            List<String> boxColors = input.get(box);
            if(colorIndex >= colors.size()) {
                colorIndex = 0;
            }
            String color = colors.get(colorIndex++);
            // a combination is generated only if the actual
            // colors does exist in the actual box 
            // and it has not already been generated i all previous rows
            if(boxColors.contains(color) && isNotYetGenerated(box, color, generationHistory)) {
                row.put(box, color);
            }
        }
    }

测试PonitF

@Test
public void createFromPointF() {
    //      {box1=red, box2=blue, box3=orange}
    //      {box1=blue, box2=orange, box3=purple}
    //      {box1=red, box3=pink}
    //      {box3=red, box1=orange}
    //      {box3=blue}

    //      0,0    {box1=red}
    //      0,1    {box1=blue}
    //      0,2    {box1=orange}
    //      0,x    {box1=purple}
    //      0,x    {box1=pink}
    //
    //      1,0    {box2=red}
    //      1,1    {box2=blue}
    //      1,2    {box2=orange}
    //      1,x    {box2=purple}
    //      1,x    {box2=pink}
    //
    //      2,0    {box3=red}
    //      2,1    {box3=blue}
    //      2,2    {box3=orange}
    //      2,3    {box3=purple}
    //      2,4    {box3=pink}

    //      0,0     1,1     2,2
    //      0,1     1,2     2,3
    //      0,x     1,x     2,0
    //      0,x     1,0     2,1

    Map<String, List<String>> input = new LinkedHashMap<>();
    input.put("box1", Arrays.asList("red", "blue", "orange"));
    input.put("box2", Arrays.asList("red", "blue", "orange"));
    input.put("box3", Arrays.asList("red", "blue", "orange", "purple", "pink"));

    List<Map<String, String>> output = create(input);
    Assert.assertEquals(
            "{box1=red, box2=blue, box3=orange}\r\n" + 
            "{box1=blue, box2=orange, box3=purple}\r\n" + 
            "{box1=orange, box3=pink}\r\n" + 
            "{box3=red}\r\n" + 
            "{box2=red, box3=blue}\r\n", toString(output));
}

private String toString(List<Map<String, String>> output) {
    StringWriter sw = new StringWriter();
    for(Map<String, String> e : output) {
        sw.write(e.toString());
        sw.write("\r\n");
    }
    return sw.toString();
}

<强> OuputF

{box1=red, box2=blue, box3=orange}
{box1=blue, box2=orange, box3=purple}
{box1=orange, box3=pink}
{box3=red}
{box2=red, box3=blue}

答案 1 :(得分:0)

您可能会考虑以下策略(代码未提供,因为这是“家庭作业”):

  1. 创建一个有颜色的Ball
  2. 创建一个Box类,其中包含一个球数的计数方法,以及一个addBall方法
  3. 在Box中创建一个“选择”方法,你给出一个球数组,它会从一个与球阵列输入上的任何颜色都不匹配的hte框中拉出一个球,或者为空。
  4. 通过创建列(框中包含最大球数的大小)开始处理输出,然后第1行从框1中拉出一个球,该球没有来自先前拉球的球颜色) 对于第2行从框2中拉出一个没有颜色的球) ...

答案 2 :(得分:0)

如果我正确理解了这个问题,你可以做的是:

  1. 按照盒子中的球数对盒子进行排序(从最小到最大的盒子上升)。
  2. 虽然还有颜色
  3. 遍历已排序的框列表
  4. 在每次迭代中从框中选择一种颜色(如果还有一个),在当前迭代(while循环)中尚未选择颜色
  5. 希望这会有所帮助。没有密码,不得不睡觉。

    编辑:这是伪代码:

    arranged_colors = [] // empty list, this is you desired output
    sort_the_boxes(boxes) // ascending, by the number of colors in it
    while( there_are_more_colors_left() ) { // a method that is easy to implement
      current_list = [] // empty list
      for( box in boxes ) {
        for( color in box ) {
          if( not color in current_list ) {
            current_list.add(color)
            box.remove(color)
            break
          }
        }
      }
      aranged_colors.add(current_colors)
    }