【发布时间】:2017-08-18 15:08:12
【问题描述】:
这是我的一个朋友给我的一个挑战。我设法提出了一个递归算法,它适用于小输入,但是我得到大值的分段错误。我想这是因为堆栈溢出。我用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 个数组,一个不包括总和的第一项,一个不包括第二项,这样我们就可以从子集中排除这些对。然后对他们俩的第一个数组做同样的事情。如果我们检查了数组中的所有元素,则将解决方案设置为数组的长度,并继续将“求解器”应用于长度大于已找到解决方案的数组。该算法适用于 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;
}
【问题讨论】:
-
您是否专门寻找相同算法的非递归实现?或者您是否愿意接受完全不同的算法以更有效的方式解决同一问题?
-
我提到我希望看到任何解决方案,我只是好奇如何将其转换为迭代算法。在处理由于堆栈溢出导致的分段错误时,这似乎是我通常具备的一项重要技能。
-
哦,对不起,我现在看到那是在代码转储之前的最后一句话中(“我希望看到任何解决方案,但是我更希望看到如何将此算法转换为迭代一”)。问题是这是两个非常不同的问题。
-
好的,我已尝试将其限制为一个问题,如果需要进一步编辑,请通知我。
-
有点OT:
subset是连续的还是集合的一部分,换句话说,对于输入1 7 4 2,7 2是不是一个子集?
标签: c arrays algorithm recursion segmentation-fault