数组分区最小差异

时间:2016-05-06 16:17:00

标签: java c# algorithm

我需要根据C#/ Java中的最小差异对数组数据进行分区。

<input>

e.g。

  • B3,D4之间的差异= | 3 - 4 | = 1

  • A23,B25之间的差异= | 23 - 25 | = 2

  • D4,C7之间的差异= | 4 - 7 | = 3

  • B12,A12之间的差异= | 12 - 12 | = 0

规则是:

  • 对于每个小组,信件不能重复

  • 对于每个组,它可以包含1到4个元素

  • 元素之间的差异必须为&lt; = 3

$(document).ready(function($){

  var options = $.makeArray( $('.showSection') );

  function doStuff() {
    var that;
    if (this === window) {
      that = options[0];
      options.push(options.shift());
    } else {
      that = this;
    }

    $(that).addClass('selected').siblings().removeClass('selected');
    $('.targetSection').hide();
    jQuery('#div' + jQuery(that).data('target')).show();
  }

  $('.showSection').on('click', doStuff); 

  setInterval(doStuff, 5000);

  $('.showSection').first().click();
});

2 个答案:

答案 0 :(得分:1)

您提供的输入包含多个解决方案。可能大约15左右(A1-A2,A35-A36,D4-C7将改变解决方案)。因为当我问你想要哪个解决方案时你没有回答,我写了这个代码,它将给出一个(最简单的)&#34;解决方案&#34;对于这个问题=)

static string[][] Solve(string[] input)
{
    List<string> myList = new List<string>(input);
    List<string[]> groups = new List<string[]>();
    while (myList.Count > 0)
    {
        string currentStr = myList[0];
        int currentNum = int.Parse(currentStr.Substring(1));
        List<string> lessThan4 = new List<string>();
        lessThan4.Add(currentStr);
        for (int i = 1; i < myList.Count; i++)
        {
            if (Math.Abs(currentNum - int.Parse(myList[i].Substring(1))) < 4)
            {
                // Add it to the list only if there's not the same letter in there
                if (!lessThan4.Where(a => a.Contains(myList[i].Substring(0, 1))).Any())
                {
                    lessThan4.Add(myList[i]);
                }
            }
        }

        lessThan4.Sort();
        groups.Add(lessThan4.ToArray());
        myList = myList.Except(lessThan4).ToList();
    }
    return groups.ToArray();
}

您可以使用以下内容进行测试:

string[] input = new string[] { "A2", "B3", "D4", "C7", "B12", "A12", "C14", "D15", "C22", "A23", "B25", "A35", "A36", "D37" };
Solve(input);

在这种情况下Solve()的输出将是:

{ A2, B3, D4 },{ C7 },{ B12, A12, C14, D15 },{ C22, A23, B25 },{ A35, D37 },{ A36 }

重要提示:此代码假定输入内的字符串是唯一的。

答案 1 :(得分:1)

Dyalog APL并行数组处理语言编写代码只花了10分钟,但我花了2个小时写下答案。我根本不会提交任何代码,所以不要打破问题中的语言限制,但我会尝试使用数据和一些伪代码来澄清下面的原则。

提供参数固定顺序,有512种可能的解决方案,如下所示:

┌──────────┬─┬─┬──┬──┬───┬───┬──┬──┬──┬──┬─────┐
│Partitions│6│7│8 │9 │10 │11 │12│13│14│15│Total│
├──────────┼─┼─┼──┼──┼───┼───┼──┼──┼──┼──┼─────┤
│Solutions │1│9│36│84│126│126│84│36│9 │1 │512  │
└──────────┴─┴─┴──┴──┴───┴───┴──┴──┴──┴──┴─────┘

具有最小分区(6)的解决方案是:

┌──┬───────────┬───────────────┬───────────┬───┬───────┐
│A1│A2 B3 D4 C7│B12 A12 C14 D15│C22 A23 B25│A35│A36 D37│
└──┴───────────┴───────────────┴───────────┴───┴───────┘

下一个(有7个分区)是:

┌──┬───────────┬───────────────┬───────────────┬───────────┬───┬───────┐
│A1│A2 B3 D4 C7│B12 A12 C14 D15│C22 A23 B25    │A35        │A36│D37    │
├──┼───────────┼───────────────┼───────────────┼───────────┼───┼───────┤
│A1│A2 B3 D4 C7│B12 A12 C14 D15│C22 A23        │B25        │A35│A36 D37│
├──┼───────────┼───────────────┼───────────────┼───────────┼───┼───────┤
│A1│A2 B3 D4 C7│B12 A12 C14 D15│C22            │A23 B25    │A35│A36 D37│
├──┼───────────┼───────────────┼───────────────┼───────────┼───┼───────┤
│A1│A2 B3 D4 C7│B12 A12 C14    │D15            │C22 A23 B25│A35│A36 D37│
├──┼───────────┼───────────────┼───────────────┼───────────┼───┼───────┤
│A1│A2 B3 D4 C7│B12 A12        │C14 D15        │C22 A23 B25│A35│A36 D37│
├──┼───────────┼───────────────┼───────────────┼───────────┼───┼───────┤
│A1│A2 B3 D4 C7│B12            │A12 C14 D15    │C22 A23 B25│A35│A36 D37│
├──┼───────────┼───────────────┼───────────────┼───────────┼───┼───────┤
│A1│A2 B3 D4   │C7             │B12 A12 C14 D15│C22 A23 B25│A35│A36 D37│
├──┼───────────┼───────────────┼───────────────┼───────────┼───┼───────┤
│A1│A2 B3      │D4 C7          │B12 A12 C14 D15│C22 A23 B25│A35│A36 D37│
├──┼───────────┼───────────────┼───────────────┼───────────┼───┼───────┤
│A1│A2         │B3 D4 C7       │B12 A12 C14 D15│C22 A23 B25│A35│A36 D37│
└──┴───────────┴───────────────┴───────────────┴───────────┴───┴───────┘

最后一个(分为15个分区)很自然:

┌──┬──┬──┬──┬──┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│A1│A2│B3│D4│C7│B12│A12│C14│D15│C22│A23│B25│A35│A36│D37│
└──┴──┴──┴──┴──┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘

解决此问题的最佳,最安全的方法是使用蛮力并遍历所有可能性。首先,您需要调整使用零和一的原则来指示分区位置。由于参数中有15个元素,我们使用15个长度的二进制向量来完成这项工作。例如:

(1 0 0 1 0 0 0 0 1 0 0 1 0 0 0) partition 'stackoverflowex'

暗示/将返回4个分区:

┌───┬─────┬───┬────┐
│sta│ckove│rfl│owex│
└───┴─────┴───┴────┘

您还可以对另一个15长度的布尔矢量进行分区:

(1 0 0 1 0 0 0 0 1 0 0 1 0 0 0) partition (1 1 0 0 1 1 0 1 0 0 0 1 1 0 0)

应返回:

┌─────┬─────────┬─────┬───────┐
│1 1 0│0 1 1 0 1│0 0 0│1 1 0 0│
└─────┴─────────┴─────┴───────┘

您可以计算每个分区中的总和。上面的那个将返回:

┌─┬─┬─┬─┐
│2│3│0│2│
└─┴─┴─┴─┘

要解决您的问题,您必须生成所有可能的分区向量。这比做起来更简单。您只需要这两者之间的所有分区向量:

1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 // This would create 1 single, big partition
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 // This would create 15 small partitions

这些是什么?非常简单,它们是16384和32767的2基(二进制)表示。您必须简单地遍历 16384和32767之间的所有数字(包括两者),将每个数字转换为2-base,分区您的数据,并查看当前分区是否可接受(=符合您的标准,如“对于每个组,信不能重复”)。转换区间中的所有数字将覆盖所有可能的分区 - 任何可能的零和1组合都在那里。计算只需要一秒钟的片段。

伪:

// The character part of the argument: 15-length vector of characters:
Chars = "A","A","B","D","C","B","A","C","D","C","A","B","A","A","D" 

// From that, extract the locations of the unique characters:
CharsA = 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0 // Where Chars == A
CharsB = 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0 // Where Chars == B
CharsC = 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0 // Where Chars == C
CharsD = 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1 // Where Chars == D

// The numeric part of the argument: 15-length vector of numbers:
// Btw, is this about lottery... hmmm
Nums = 1, 2, 3, 4, 7, 12, 12, 14, 15, 22, 23, 25, 35, 36, 37

:For Number :In [all numbers between 16384 and 32767]

    Base2 = [2-base of Number] // 20123 would give: 1 0 0 1 1 1 0 1 0 0 1 1 0 1 1

    // Test 1: "For each group, it can contains 1 - 4 elements"
        [using Base2, partition the partition vector Base2 itself;
         bail out if any partition length exceeds 4]

    // Test 2: "Difference between element must be <= 3"
        [using Base2, partition Nums; 
         check differences inside each partition; 
         bail out if bigger than 3 anywhere]

    // Test 3: "For each group, letter cannot be repeated"
        [using Base2, partition CharsA, CharsB, CharsC, CharsD (each in turn);
         count number of ones in each partition;
         bail out if exceeds 1 anywhere (meaning a character occurs more than once)]

    // If we still are here, this partition Number is ACCEPTABLE
    [add Number to a list, or do a parallel boolean marking 1 for Number]

:End

此时,512 Number已满足指定的条件,而其余的则在某些测试中失败。这是一个纯粹的巧合,它们是512,这对于我们的编码员来说是一个特殊的数字。假设您现在在变量中有512个可接受的数字,名为结果。现在,您需要通过解析每个Result中的分区数(=其二进制表示中的分区数)对其进行排序。通过再次将Result中的每个数字转换为base 2,然后计算&amp;将每个中的一个数加起来,按该总和升序排序。最小的总和将是6,它只出现一次 - 这是在这个答案的顶部提到的分区。

它的值是25126,而2的基础是

1 1 0 0 0 1 0 0 0 1 0 0 1 1 0