C函数使用加法和减法获取数组的所有总和
Posted
技术标签:
【中文标题】C函数使用加法和减法获取数组的所有总和【英文标题】:C function to get all sums of an array using addition and subtraction 【发布时间】:2022-01-08 10:07:38 【问题描述】:使用加法和减法来获得数组中所有 N 个数字的总和的最佳方法是什么(在 C 中)?
例如(N = 3):
arr[] = [30, 14, 2]
results:
-30-14-2 = -46
-30-14+2 = -42
-30+14-2 = -18
-30+14+2 = -14
30-14-2 = 14
30-14+2 = 18
30+14-2 = 42
30+14+2 = 46
可以看出,有2^N个解。
我还注意到,加法和减法符号的交替方式与二进制计数 (000 001 ... 110 111) 相同,这可能很有用。
也许递归方法是最好的,但我发现递归思考非常困难。
因此,我希望有人能向我解释解决这个问题的最佳策略是什么。
—————————
编辑:
我有一个可用的 Python 代码,但这使用了集合 set()
,这在 C 中不可用。(arr
是一个包含所有数字的数组。)
out = set()
out.add(0)
for i in range(0, len(arr)):
tmp = set()
for j in out:
tmp.add(j + arr[i])
tmp.add(j - arr[i])
out = tmp
print(out)
—————————
编辑:
通过用数组替换集合并进行一些小的更改,我得到了它的工作。感谢所有评论的人!
【问题讨论】:
这是一个观点:你不应该递归地这样做,而只是在两个循环中......一个循环操作(因为它们可以用累加器完成)和第二个循环值,您将获得结果而不会遇到内存问题。 建议:1) 我会考虑将此作为permutations 问题的重点。 2)我不知道递归是否“更好”,但是你可以用递归做任何事情,你也可以用循环做。 3)我不确定是否一定有 2^N 个“解决方案”。例如,“a+b”==“b+a”(它们是“相同的”);但是“a-b”“b-a”(它们是两种不同的“解决方案”)。 不用集合,只用一个数组。性能在这里有多重要? 如果您有解决方案,请考虑发布self answer 以帮助其他有同样问题的人。 有趣的是,结果的下半部分是上半部分的 (-1)。看起来你只需要做一半的数学,然后(-1)整个解决方案。 【参考方案1】:在这种情况下,递归似乎比数据结构更可取,因为问题的指数性质意味着您可以实际测试的任何 n
值都没有堆栈溢出的风险,但您可以利用堆栈的优势隐式存储功能。
可以使用索引i
非常直接地编写递归逻辑。基本情况是i >= n
;打印您累积的总和。否则,从总和中减去i
th 元素并在没有i
的数字列表的其余部分上递归。在第二个分支中,将i
th 元素添加到总和中,并在没有i
的数字列表的其余部分上递归。如果 i
如 cmets 中指出的那样,您也可以使用指针将元素移出数组。
请注意,此过程将包含重复的结果,因此如果您想消除这些重复的结果,您最初的设定想法值得追求。
在函数中混合 IO 和逻辑通常是糟糕的设计,但为了简单起见,我将在这里打破这条规则:
#include <stdio.h>
void print_possible_sums(int nums_len, int *nums, int sum, int i)
if (i >= nums_len)
printf("%d\n", sum);
else
print_possible_sums(nums_len, nums, sum - nums[i], i + 1);
print_possible_sums(nums_len, nums, sum + nums[i], i + 1);
int main()
int arr[] = 30, 14, 2;
print_possible_sums(sizeof(arr) / sizeof(arr[0]), arr, 0, 0);
return 0;
输出:
-46
-42
-18
-14
14
18
42
46
【讨论】:
也许我应该感到受宠若惊,但你可以提到你的inspiration? @EOF 我不确定我是否按照您的提示进行操作,但是指针的想法是一个不错的改进,感谢分享。 真是不可思议,我们的编程风格如此相似。 你是在暗示我复制它吗?如果是这样,情况并非如此,我不确定我是如何找到该链接的。问题很简单,所以解决方案也很直接,所以我不确定会有多大的偏差空间。【参考方案2】:我已经制作了一个算法来解决这个问题。也许我写的不是尽可能高效(所以也许可以改进),但至少它是有效的。
让我知道是否可以。
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define MAX 4
void cycle(int arr[MAX]);
int toRepeat(int arr[MAX], int s);
int main()
int arr[MAX] = 1, 2, 3, 4;
cycle(arr);
void cycle(int arr[MAX])
int a, ris;
a = pow(2, MAX);
for (int i= 0; i < a; i++)
ris = toRepeat(arr, i);
printf(" = %3d \n", ris);
int toRepeat(int arr[MAX], int s)
int pos = 0;
int ris = 0;
int a;
bool flag;
a = pow(2, MAX);
if (s < a/2)
ris += arr[pos];
printf("+%d", arr[pos]);
else
ris -= arr[pos];
printf("-%d", arr[pos]);
pos++;
for (int i= 2; i < a; i = i * 2)
for (int j= 0; j < i/2; j++)
if (s%i == j)
ris += arr[pos];
printf("+%d", arr[pos]);
pos++;
flag = true;
break;
if (!flag)
ris -= arr[pos];
printf("-%d", arr[pos]);
pos++;
flag = false;
return ris;
输出:
+1+2+3+4 = 10
+1-2+3+4 = 6
+1+2-3+4 = 4
+1-2-3+4 = 0
+1+2+3-4 = 2
+1-2+3-4 = -2
+1+2-3-4 = -4
+1-2-3-4 = -8
-1+2+3+4 = 8
-1-2+3+4 = 4
-1+2-3+4 = 2
-1-2-3+4 = -2
-1+2+3-4 = 0
-1-2+3-4 = -4
-1+2-3-4 = -6
-1-2-3-4 = -10
【讨论】:
为了微笑,我用原始数据集编译了你的代码(我需要做一些小改动),并确认它给出了预期的结果:+30+14+2 = 46 +30-14+2 = 18 +30+14-2 = 42 +30-14-2 = 14 -30+14+2 = -14 -30-14+2 = -42 -30+14-2 = -18 -30-14-2 = -46
【参考方案3】:
我也是,我也是!
使用bool negative[3 + 1] = 0;
保留一个数组。在每一步计算array[i] * (negative[i]?-1:1)
的总和。每一步都会以负数递增下一个值,就好像它是一个二进制数一样。当最高元素 negative[3]
为真时,循环结束 - 所以我们想要通过所有可能性。
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <assert.h>
int calc_sum(size_t len, const int vals[len], const bool negative[len])
int sum = 0;
for (size_t i = 0; i < len; ++i)
sum += vals[i] * (negative[i] ? -1 : 1);
return sum;
bool *sequence_init(size_t len)
// error checking omitted
return calloc(len + 1, sizeof(bool));
bool sequence_continue(size_t len, bool t[len + 1])
assert(t);
const bool go_on = !t[len];
if (!go_on)
// automatically free on loop end
free(t);
return go_on;
void sequence_next(size_t len, bool t[len + 1])
assert(t);
for (size_t i = 0; i < len + 1; ++i)
if (!t[i])
t[i] = 1;
break;
else
t[i] = 0;
int main()
const int vals[3] = 30, 14, 2 ;
const size_t len = 3;
for(
bool *sequence = sequence_init(len);
sequence_continue(len, sequence);
sequence_next(len, sequence)
)
for (size_t i = 0; i < len; ++i)
printf("%2d*%d %c ",
sequence[i]?-1:1,
vals[i],
i + 1 != len ? '+' : '='
);
const int sum = calc_sum(len, vals, sequence);
printf("%d\n", sum);
代码输出:
1*30 + 1*14 + 1*2 = 46
-1*30 + 1*14 + 1*2 = -14
1*30 + -1*14 + 1*2 = 18
-1*30 + -1*14 + 1*2 = -42
1*30 + 1*14 + -1*2 = 42
-1*30 + 1*14 + -1*2 = -18
1*30 + -1*14 + -1*2 = 14
-1*30 + -1*14 + -1*2 = -46
【讨论】:
以上是关于C函数使用加法和减法获取数组的所有总和的主要内容,如果未能解决你的问题,请参考以下文章