需要有关算法的帮助(堆栈溢出)

时间:2017-03-25 18:47:46

标签: c arrays algorithm recursion segmentation-fault

这是一个我的朋友给我带来挑战的问题。我设法提出了一种适用于小输入的递归算法,但是我得到大值的分段错误。我认为这是因为堆栈溢出。我使用C语言来解决问题。

您将获得一系列n个数字。查找并打印子集的最大长度,使得对于形成该子集的任何两个数字,数字的总和不能被k整除。

输入包含第一行2个数字n和k,在下一​​行有n个数字a [i],使得:

1 <= n <= 10^5
0 <= a[i] <= 10^9
1 <= k <= 100

# Example input:
4 3
1 7 4 2

# Output:
3

说明:(1 7 4) 1 + 7 = 8; 1 + 4 = 5; 7 + 4 = 11;所有这些都不能被3整除。

我的解决方案基于以下想法:对于数组中的所有数字,如果它可以被k整除,则检查与其他数字的总和。如果我们找到匹配然后创建2个数组,一个排除和的第一个项,一个排除第二个,这样我们从子集中排除这些对。然后对第一个数组做同样的事情。如果我们检查了数组中的所有元素,那么将解决方案设置为数组的长度并继续应用&#34;求解器&#34;仅限长度大于已找到的解决方案的数组。该算法适用于n

#include <stdio.h>

int n, k;

int * deleteElement(int * a, int n, int j){
    int *c = (int*) malloc((n-1) * sizeof(int));
    int k = 0;
    for(int i = 0; i < n; i++){
        if(i == j) continue;
        c[k] = a[i];
        k++;
    }
    return c;
}

int sol = 0;

void solver(int *a, int n, int *sol){
    int *b, *c;
    if(n <= *sol) return;
    for(int i = 0; i <  n-1; i++){
        for(int j = i + 1; j < n; j++){
             if((a[i] + a[j]) % k == 0){
                  c = deleteElement(a, n, i);
                  b = deleteElement(a, n, j);
                  solver(c, n-1, sol);
                  solver(b, n-1, sol);
                  return; 
             }
         }
     }
     *sol = n;
}

int main(){
    scanf("%d", &n);
    scanf("%d", &k);
    int a[n];
    for(int i = 0; i < n; i++) scanf("%d", &a[i]);
    solver(a, n, &sol);
    printf("%d\n", sol);
    return 0;
}

1 个答案:

答案 0 :(得分:4)

你可以使用迭代来摆脱你的两个递归调用之一,但这对堆栈空间没有帮助,因为它们具有相同的深度 - 一个调用与2个一样糟糕。

编写一个实际测试所有有效集的完全迭代算法很容易,但这仍然是一个指数时间算法。在任何情况下,这都会使您免于堆栈溢出,运行 way 的时间太长。由于该算法也很糟糕,我不想写它。

解决此问题的合理线性时间方法是:

  1. 计算地图MODCOUNTS,其中MODCOUNTS [m] =元素数x,使得x%k == m
  2. 由于任何有效子集只能有一个可被k整除的元素,如果MODCOUNTS [0]&gt; 1,然后设置MODCOUNTS [0] = 1
  3. 类似地,如果k是偶数,并且MODCOUNTS [k / 2]> 1,然后设置MODCOUNTS [k / 2] = 1
  4. 现在,将MODCOUNTS中的所有值相加,但如果出现以下情况,则省略值MODCOUNTS [i]:
    • i&gt; 0,i * 2&lt; k,AND MODCOUNTS [i]&lt; MODCOUNTS [K-1]; OR
    • i * 2&gt; k和MODCOUNTS [i]&lt; = MODCOUNTS [k-i]
  5. 规则4反映了这样一个事实:对于我们在规则2和3中没有处理的情况,有效子集不能包括任何元素x和y,使得(x + y)%k = 0。最大的有效子集包括MODCOUNTS [i]中的所有元素,或MODCOUNTS [ki]中的所有元素,但不包括两者中的元素。

    如果使用稀疏数据结构(如哈希表)来实现MODCOUNTS,则整个过程需要O(N)时间。