# 每日一练——从长度为n的数组里选出m个数使和为固定值sum

vector<int> twoSum(vector<int>& nums, int target) {
vector<int> result;
map<int, int> cache;//第一个为数字，第二个为下标
int max_index = nums.size()-1;
for (int i = 0 ; i <= max_index; i++)
{
cache[nums[i]] = i;
}

map<int, int>::iterator iter;

for (int i = 0 ; i <= max_index; i++)
{
iter = cache.find(target - nums[i]);

if(iter != cache.end() && iter->second != i)
{
result.push_back(nums[i]);
result.push_back(iter->first);
break;
}
}
return result;
}

void CalSum(vector<int> &nums, int result)
{
int len = nums.size();
int *dp = new int[result + 1];
dp[0] = 1;
for (int i = 1; i <= len; i++)
{
dp[i] = 0;
}
vector<int> *p = new vector<int>[result + 1];

for ( i = 0; i < len; i++)
{
for (int j = result; j >= nums[i]; j--)
{
if (dp[j] < dp[j - nums[i]])
{
dp[j] = dp[j - nums[i]];
p[j] = p[j-nums[i]];
p[j].push_back(nums[i]);
}
}
}
if (dp[result] == 1)//如果存在某些物品使得容量为result的背包恰好装满则输出。
{
for (vector<int>::iterator iter = p[result].begin(); iter != p[result].end(); iter++)
{
cout << *iter << " ";
}
cout << endl;
}
delete []dp;
delete []p;
}

void combination(vector<int>& candidates, int start, int end, int target, vector<int> &tmp, vector<vector<int> > &result)
{
if (target == 0)
{
result.push_back(tmp);
return;
}
if (start > end)//如果start超过end还没达到目标，那么就直接去掉
{
return ;
}
for (int i = start; i <= end; i++)
{
tmp.push_back(candidates[i]);
combination(candidates, i + 1, end, target - candidates[i], tmp, result);
tmp.pop_back();
while(i < end && candidates[i] == candidates[i+1])//去掉重复的组合
{
i++;
}
}
}

vector<vector<int> > CalSum(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
vector<vector<int> > result;
vector<int> tmp;
int end = candidates.size() - 1;
combination(candidates, 0, end, target, tmp, result);
return result;
}

if (target == 0)
{
if (tmp.size == m)
{
result.push_back(tmp);
}
return;
}

void CalSum(vector<int> &nums, int result)
{
int len = nums.size();
int bit = 1 << len;
for (int i = 1; i < bit; i++)//从1循环到2^N
{
int sum = 0;
vector<int> tmp;
for (int j = 0; j < len; j++)
{
if ((i & 1 << j) != 0)//用i与2^j进行位与运算，若结果不为0,则表示第j位不为0,从数组中取出第j个数
{
sum += nums[j];
tmp.push_back(nums[j]);
}
}
if (sum == result)
{
for (vector<int>::iterator iter = tmp.begin(); iter != tmp.end(); iter++)
{
cout << *iter << " ";
}
cout << endl;
}
}
}

void CalSum(vector<int> &nums, int result)
{
int len = nums.size();
int bit = 1 << len;
sort(nums.begin(), nums.end());//对数组排序
for (int i = 1; i < bit; )//从1循环到2^N
{
int sum = 0;
vector<int> tmp;
for (int j = 0; j < len; j++)
{
if ((i & 1 << j) != 0)//用i与2^j进行位与运算，若结果不为0,则表示第j位不为0,从数组中取出第j个数
{
sum += nums[j];
tmp.push_back(nums[j]);
}
}
if (sum == result)
{
i = i | (i - 1);//剪枝优化
for (vector<int>::iterator iter = tmp.begin(); iter != tmp.end(); iter++)
{
cout << *iter << " ";
}
cout << endl;
}
i++;
}
}
Ok，这样做乍一看没啥问题，后来仔细想想我被这个评论坑了，假如数组是{-8, -7 , -1, 1}，sum为-15，当数字为1100时就已经算出-15了，按照评论，后面的1101、1110、1111是不用看的，其实我们看到1111算出来的值也是-15，后面的两个数一正一负恰好抵消。评论所说的优化只有在数组中的数全部为正数或者全部为负数才能够适用。在数组中的数字不确定正负时还是以第三个代码为准：）。

int NumOf1(int num)
{
int count = 0;
while (num)
{
num = num & (num - 1);
count++;
}
return count;
}

void CalSum(vector<int> &nums, int result, int m)
{
int len = nums.size();
int bit = 1 << len;
for (int i = 1; i < bit; i++)//从1循环到2^N
{
int sum = 0;
vector<int> tmp;
if (NumOf1(i) == m)
{
for (int j = 0; j < len; j++)
{
if ((i & 1 << j) != 0)//用i与2^j进行位与运算，若结果不为0,则表示第j位不为0,从数组中取出第j个数
{
sum += nums[j];
tmp.push_back(nums[j]);
}
}
if (sum == result)
{
for (vector<int>::iterator iter = tmp.begin(); iter != tmp.end(); iter++)
{
cout << *iter << " ";
}
cout << endl;
}
}
}
}