面试题:检查一个数组里是否存在m个数的和等于某个值

来源:互联网 发布:netsh 查看端口 编辑:程序博客网 时间:2024/06/05 19:13

检查一个数组里是否存在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 个数的和等于某个值 SUMbool 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{// sortSort::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;}}}}



1 0