描述
给一整数 n
, 我们需要求前n个自然数形成的集合的所有可能子集中所有元素的和。
您在真实的面试中是否遇到过这个题?
是
样例
给出 n = 2, 返回 6
可能的子集为 {{1}, {2}, {1, 2}}.
子集的元素和为 1 + 2 + 1 + 2 = 6
给出 n = 3, 返回 24
可能的子集为 {{1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}}
子集的和为:
1 + 2 + 3 + (1 + 2) + (1 + 3) + (2 + 3) + (1 + 2 + 3) = 24
这其实是一道可以投机取巧的数学题,其实每个数字出现的次数是一样的,只需要计算它们出现了多少次,而这是一个组合问题。
然后我就这样写了:
class Solution {
public:
/**
* @param n: the given number
* @return: Sum of elements in subsets
*/
int subSum(int n) {
// write your code here
long long sum=0;
long long tsum=0;
for(int m=1;m<=n;m++){
if(m==1||m==n) sum+=1;
else {
long long nsum=1;
long long msum=1;
for(int i=m-1;i>0;i--) msum*=i;
for(int i=n-1;i>=n-m+1;i--) nsum*=i;
sum+=nsum/msum;
}
}
for(int i=1;i<=n;i++) tsum+=i;
return sum*tsum;
}
};
接着,它就超时了。。。我就知道,这个for循环带给我的只能是超时。
所以换思路,不直接计算出现个数,用递推的方式算。新集合的子集是:
1.原来的子集 2.原来的子集 每个集合都加上3 3.新集合自己
新集合的和,原来的集合的和*2 加上 n*pow(2,n-1) 因为集合数的和是2^n。
class Solution {
public:
/**
* @param n: the given number
* @return: Sum of elements in subsets
*/
int subSum(int n) {
// write your code here
if(0 == n) return 0;
long long int result = 0;
result = subSum(n - 1) * 2 + n * static_cast<long long>(pow(2, n-1));
return result;
}
};