检查一个数组里是否存在m个数的和等于某个值
个人信息:就读于燕大本科软件工程专业 目前大三;
本人博客:google搜索“cqs_2012”即可;
个人爱好:酷爱数据结构和算法,希望将来从事算法工作为人民作出自己的贡献;
编程语言:C++ ;
编程坏境:Windows 7 专业版 x64;
编程工具:vs2008;
制图工具:office 2010 powerpoint;
硬件信息:7G-3 笔记本;
真言
题目别人吃不了的苦,我能吃;别人受不了的罪,我能受;别人觉得委屈了,我没有;不求别的,只求自己比别人更坚强,对得起父母给自己起的名字。
方案检查一个数组里是否存在m个数的和等于某个值
此题前面有一个题目,检查数组里是否存在两个数的和等于某个值
这个题目的解法
1)先给数组排序,时间复杂度为排序的时间复杂度(根据自己选择的排序方法而定)
2) 双向遍历:数组里最大值与最小值的和 sum 与 给定值 k 的 关系 ,时间复杂度为O(n )
while( 最小值 < 最大值 )
{
if( sum == k)
return true;
else if(sum < k)
{
舍弃最小值,更新最小值:取比最小值大的最小值
}
else 舍弃最大值,更新最大值: 取比最大值小的最大值
}
3)C++ 表示算法如下,这里我使用的是计数排序
// 求出两个数之和为定值的两个数 std::pair<int,int> Array::SumKOfTwo(int * data,unsigned int const length,int sum) { // 异常输入 if(data == NULL || length == 0) { cout<<"error input of SumK,data = "<<data<<" ,length= "<<length<<endl; return std::make_pair(-1,-1); } // 正常输入 else { std::pair<int,int> result = MaxMin(data,length); // 元素里的值都相同 if(result.first == result.second) { if(sum == 2*(result.first)) return result; else { cout<<"不存在两个数的和等于"<<sum<<endl; return std::make_pair(-1,-1); } } // 元素里的值有不一样的 else { Sort::Count_sort(data,length); unsigned int i=0,j=length-1; while(i<=j) { if( data[i]+data[j] == sum ) { return std::make_pair(data[i],data[j]); } else if( data[i]+data[j] < sum ) { i++; } else j--; } // 如果不存在答案 cout<<"不存在两个数的和等于"<<sum<<endl; return std::make_pair(-1,-1); } } }
问题扩展:是否存在多个数的和等于某个值呢
暴力法就太麻烦了,这里我自己想出一种贪心的方法,利用了stack,并修改了工具栈,从这里凸显出我对数据结构的灵活运用
举个例子吧, 数组为 11,45,34,23,17,23,45,27,34,给定值为 106(即为 45 + 34 +27)
数组排序后为 11,17,23,23,27,34,34,45,45
我设计的的算法是这样的,工具栈初始化及变化如下
1.
11 < 106, 插入 17
2.
28 < 106, 插入23
3.
51 < 106, 插入 23
4.
74 < 106, 插入 27
5.
103 < 106 ,插入 34
6.
137 > 106, 出栈 34,然后把栈顶 27 扩大一下,换成其在数组里后面的值 34
7.
110 > 106 , 出栈 34,然后把栈顶 23 扩大一下,换成其在数组里后面的值 27
8.
78 < 106 , 34 进栈
9.
112 > 106 , 出栈 34,然后把栈顶 27 扩大一下,换成其在数组里后面的值 34
10.
85 < 106 ,34 进栈
11.
119 > 106, 出栈 34,然后把栈顶 34 扩大一下,换成其在数组里后面的值 34
12.
85 < 106 , 45 进栈
13.
130 > 106,出栈 45,然后把栈顶 34 扩大一下,换成其在数组里后面的值 45
14.
96 < 106 ,45 进栈
15.
141 > 106 ,出栈 45,然后把栈顶 45扩大一下,换成其在数组里后面的值 45
16.
96 < 106, 但此时 栈顶已经是数组里最后一个值,所以不再进栈而是 出栈 45,然后把栈顶 23扩大一下,换成其在数组里后面的值 23
相信大家已经看到我算法的规律了,说到这里实在不好意思,例子找的不好,弄得非常长,大家看懂得感觉很简单,看不懂感觉很恶心
直到最后我的栈 会变到一下情况,就是出口
例子不好之处,还请见谅,下面给出我的算法(C++代码表示)
// 求出数组里是否存在 n 个数的和等于某个值 SUM bool Array::Is_Sum_SomeData(int *data,unsigned int const length,unsigned int SUM) { // 异常输入 if(data == NULL || length == 0) { cout<<"error input of SumK,data = "<<data<<" ,length= "<<length<<endl; return false; } // 正常输入 else { // sort Sort::Count_sort(data,length); // 创造辅助工具栈 来寻找某些值 // 对栈初始化 unsigned int _sum = 0; stack<unsigned int> * S = new stack<unsigned int>; S->push(0); _sum = data[0]; unsigned int now = S->top(); // 核算算法 while(true) { // 进栈决策 if( _sum < SUM ) { // 有元素可以进栈 now++; if(now < length) { S->push(now); _sum += data[now]; } // 没有元素可以进栈 else{ // 出口:并且栈空了,那就没有答案了 if(S->empty() == true) { return false; } // 栈不空时,把栈顶后移一位 else{ now = S->top(); S->pop(); _sum -= data[now]; } } } // 出栈决策 else if(_sum > SUM) { // 出口:只有一个值,并且还大于要求的和,那就没有答案了 if(S->size() < 2) return false; // 否则出栈寻找个数更小,数更大的值去做 // 出栈两个(进栈一个) else { _sum -= data[S->top()]; S->pop(); _sum -= data[S->top()]; now = S->top(); S->pop(); } } // 出口:找到答案 else { return true; } } } }