C - 子集的总和,需要更快的算法

时间:2016-12-01 16:04:13

标签: c algorithm

我试图找到等于给定数字的子集(1-3长度)。我写了这个算法,它工作正常但速度太慢。我如何更改此算法以使其更快?

int PrintCombinations(int * array, int userLenght) {
    int total = 0;

    for (int i = 0; i < GetArrayLenght(array); ++i) {
        if(userLenght == array[i]) {
            printf("%d = %d\n", userLenght, array[i]);
            ++total;
        }
    }

    for (int j = 0; j < GetArrayLenght(array); ++j) {
        for (int k = j; k < GetArrayLenght(array); ++k) {
            if(array[j] + array[k] == userLenght) {
                printf("%d = %d + %d\n", userLenght, array[j], array[k]);
                ++total;
            }
        }
    }

    for (int l = 0; l < GetArrayLenght(array); ++l) {
        for (int i = l; i < GetArrayLenght(array); ++i) {
            for (int j = i; j < GetArrayLenght(array); ++j) {
                if(array[l] + array[i] + array[j] == userLenght) {
                    printf("%d = %d + %d + %d\n", userLenght, array[j], array[l], array[i]);
                    ++total;
                }
            }
        }
    }

    return total;
}

4 个答案:

答案 0 :(得分:1)

您应该在循环之前计算一次数组的长度。目前,它在每个循环的每次迭代中重新计算。如果此操作很昂贵,那么将计算移出循环将是优化代码的一种非常有效的方法。

例如,如果GetArrayLenght()扫描数组中的终止值,则将调用移出循环会使时间复杂度从 O(N 4 )下降 O(N 3

第二步是以不同方式嵌套循环,避免搜索子句中是否已超出长度(假设所有长度均为正数)。这不会改变时间复杂度,但仍可以显着减少测试次数:

int PrintCombinations(int *array, int userLength) {
    int total = 0;
    int length = GetArrayLenght(array); 

    for (int l = 0; l < length; ++l) {
        if (array[l] > userLength)
            continue;

        if (array[l] == userLength) {
            printf("%d = %d\n", userLength, array[l]);
            ++total;
        }
        for (int i = l; i < length; ++i) {
            if (array[l] + array[i] > userLength)
                continue;

            if (array[l] + array[i] == userLength) {
                printf("%d = %d + %d\n", userLength, array[l], array[i]);
                ++total;
            }
            for (int j = i; j < length; ++j) {
                if (array[l] + array[i] + array[j] == userLength) {
                    printf("%d = %d + %d + %d\n",
                           userLength, array[j], array[l], array[i]);
                    ++total;
                }
            }
        }
    }
    return total;
}

如果你的数组非常大,如果你可以修改它或复制它,按升序排序将降低比较次数,并使用二进制搜索最后一次循环将带来时间复杂性从 O(N 3 O(N 2 Log N)

答案 1 :(得分:0)

我会使用排序数组。一旦数组[k + 1]&gt;您就可以停止遍历userLenght。

一旦你得到'k',就把它从k遍历到0.对于2项总和,只要array[i]+array[j] < userLenght(i,j <= k)你知道那里是不可能的2项总和。 3项总和的相同技术。

BTW,在你的代码中,你需要将'for'放在'if'中,以便在我们找到总和时不要运行'for',否则'total'可能是错。

答案 2 :(得分:0)

所以,首先你按照增加顺序对数组进行排序,然后, 找到另一个数组,其中填充了长度为2的所有可能子集,称之为array2。 现在你的答案可以通过二进制搜索找到,这比你现在做的更快.. !!

编辑:

您将做的事情如下:
你正在寻找说值val.first排序原始数组。

  1. 首先在arr上进行二元搜索,寻找val,它在那里吗?如果是,则转到第2步。
  2. 搜索val作为两个元素的总和,你可以使用两个指针技术,在arr上并在线性时间得到答案,如果val作为两个元素的总和存在。如果不是,则转到步骤3。

  3. 然后首先构建arr2,arr2基本上是一个2D数组,其中第i行具有在对角元素之后开始的条目,arr2 [i] [j]将表示和arr [i] + arr [j]。再次搜索val,如何搜索?现在我们希望找到val作为三个条目的总和。所以我们遍历矩阵说你当前在arr2 [i] [j],你知道这是arr [i]和arr [j]的总和,所以从val中减去这两个条目,(这只是val-arr2 [i] [j]),并在arr中搜索结果。现在搜索arr中的结果,你不应该搜索整个数组,而是你将在两个子区间搜索结果.1。arr [i +1]到arr [j-1]
    2. arr [j + 1]到arr [n-1]
    上面的间隔确保你没有搜索重复的元素..这样做对于矩阵的所有元素,从第一个左边的条目开始,按顺序从左到右,然后是下一行,直到找到它。

  4. 的复杂性 案例1:O(nlogn)
    案例2:O(nlogn)
    案例3:O(n ^ 2)

    早些时候 案例1:O(n)
    案例2:O(n ^ 2)
    案例3:O(n ^ 3)
    所以你看到了重大进步..?

答案 3 :(得分:0)

<强>基本

  • 存储GetArrayLenght(array)的结果,因此与每个for循环的每次迭代相比,您只需要调用一次。

使用单个for循环:

for (int l = 0; l < GetArrayLenght(array); ++l)
{
    if(userLenght == array[l])
    {
        printf("%d = %d\n", userLenght, array[l]);
        ++total;
    }
    for (int i = l; i < GetArrayLenght(array); ++i)
    {
        if(array[l] + array[i] == userLenght)
        {
            printf("%d = %d + %d\n", userLenght, array[l], array[i]);
            ++total;
        }
        for (int j = i; j < GetArrayLenght(array); ++j)
        {
            if(array[l] + array[i] + array[j] == userLenght)
            {
                printf("%d = %d + %d + %d\n", userLenght, array[j], array[l], array[i]);
                ++total;
            }
        }
    }
}

高级

  • 在此函数之前对数组进行排序,然后使用二进制搜索
  • 使用多线程(OpenMP,pthread)
  • 使用GPU(OpenCL,CUDA)