用于最少调用API的算法

时间:2015-03-08 19:52:13

标签: arrays algorithm api

在我的程序中,我将有多个数组,每个字符串大约有40,000个字符串,每个字符串具有不同的长度(从10到5000个字符),我需要将此数组发送到一个只接受5 000个字符的API。

为了进行最少的API调用,我需要找到每次发送的最佳字符串组合。

例如,如果我得到一个具有不同长度{3,5,10,3,4,1,4}的数组,并且api的最大长度为10.它应该返回{10},{4 1 5} ,{3 3 4}。

我一直在寻找不同的算法,但似乎没有人满足我的需要。 (子集和其他)

非常感谢任何帮助!

5 个答案:

答案 0 :(得分:17)

您的问题是Bin Packing problem。请在下面的论文中找到非常好的解决方案:Richard Korf的A new algorithm for optimal bin packing(见示例问题)

让我们看一下数组的例子:

MAXSIZE=20
[1 2 4 5 7 10 11]

使用参考论文中的算法,您将得到:

[11 4 5] [10 7 2 1]

简而言之,这个算法通过以下方式构建bin:

  1. 插入bin最大元素

  2. 搜索适合音量的所有元素并最大化其总和

  3. 例如在我们的案例中,第一步是:

    # Take max element
    [11]
    # We have 9 volume left
    # All smaller are [1 2 4 5 7] - greedy would take 7 in this case
    # 4 and 5 sums up to 9 which is best fit in this case so first bin become:
    [11 5 4]
    # Next step: take max
    [10]
    # we have 10 volume left. elements lower than 10:
    # [1 2 7]
    # this sums up to 10 in this case giving second bin
    [10 7 2 1]
    

    只是一些贪婪的例子提到了一个:

    ARR = [3, 3, 5, 5, 5, 5, 14]
    BINSIZE = 20
    Greedy result:
    Size 3:
    [[14, 5], [5, 5, 5, 3], [3]]
    Mentioned alg result (size 2):
    [[14, 3, 3], [5, 5, 5, 5]]
    

    您也可能对维基页面上的“精确算法”部分感兴趣。

答案 1 :(得分:0)

绝对看起来像一个动态编程问题。 您的问题类似于Subset Sum problem,但不是仅查找是否存在此类子集,而是要返回所有此类子集。

这个链接似乎接近你所需要的: http://www.careercup.com/question?id=12899672

动态编程通常非常难以理解。我希望别人能提供一个彻底的解释(对我而言),但希望这能为你提供一个起点。

答案 2 :(得分:0)

这是带有变化的动态编程问题(子集和问题)。我们不仅想要找到总和是否存在,而且我们也想要找到所有不同的子集。

我们构建了一个二维布尔查询表sum(rows) - vs - number(cols),这在许多DP问题中是典型的。 为了找到与总和完全匹配的子集,我们可以在查找表上调用以下回溯函数来查找可能的有效总和。

bool backtrack(bool **subset, int sum, int a[], int n) {
    if(sum == 0) { // Sum possible
        return true;
    }
    if(sum < 0) { //Sum not possible
        return false;
    }

    for(int j=1; j<=n; j++) {
        if(subset[sum][j] == true) {
            int val = a[j-1];

            // If val is included, can we have a valid sum?
            bool valid = backtrack(subset, sum-val, a, j-1);
            if(valid == true) {
                printf("%d ", val);
                return true;
            }
        }
    }
    return false;
}

我们可以用这种方式调用上面的函数来打印出数字组合,每行一个组合 -

for(j=1; j<=n; j++) {
    if(subset[sum][j] == 1) { //For every col which is =1 for the sum'th row
       bool valid = backtrack(subset, sum-a[j-1], a, j-1);
       if(valid) {
          printf("%d\n", a[j-1]);
       }
    }
}

答案 3 :(得分:0)

这对你有什么用?显然,您可以将max更改为您想要的任何内容,并可能将其更改为从调用函数设置,但我会将这些选项留给您。

这对我有用,请告诉我你是否有任何问题。

List<List<string>> Chunk(List<string> inputStrings)
{
    List<List<string>> retVal = new List<List<string>>();

    List<string> sortedStrings = inputStrings.OrderByDescending(s => s.Length).ToList();

    while (sortedStrings.Any())
    {
        List<string> set = new List<string>();
        int max = 10;

        for (int i = 0; i < sortedStrings.Count(); ++i)
        {
            if (max == 0)
                break;
            if (max - sortedStrings[i].Length < 0)
                continue;

            set.Add(sortedStrings[i]);
            max -= sortedStrings[i].Length;
            sortedStrings.RemoveAt(i);
            --i;
        }

        if(set.Any())
            retVal.Add(set);
    }

    return retVal;
}

注意:这是C#。如果需要,我可以用其他语言或不同的数据结构重做它。

答案 4 :(得分:0)

这似乎是通过Greedy算法解决的,而不是在将字符串发送到API之前应该执行的回溯算法。