两个数之和等于第三个数 --改進版 。
来源:互联网 发布:蓝天豚硅藻泥 知乎 编辑:程序博客网 时间:2024/06/10 14:48
原題如下:给出一个有序数组,另外给出第三个数,问是否能在数组中找到两个数,这两个数之和等于第三个数
原題的解法在這裡就不重複了,算法還是很好理解的,但這種解法有個局限性,那就是對於亂序的數組就無用了,而且我還想打出所有的兩個數該怎麼辦呢?
比如:有一個數組
int arr[7] = {5,2,1,4,7,3,6};
我給定一個數為7,那麼應該輸出的是
5,2
1,6
4,3
注:2,5 = 5,2, 1,6 = 6,1 , 3,4 = 4,3
首先想到的就是用一個set,set裡面存放一個結構體,該結構體包含2個數據。代碼如下:
struct MyNum {int m_lhs;int m_rhs;MyNum(int v1, int v2) {m_lhs = v1;m_rhs = v2;}};
OK,接下來很順手的就會寫出以下的代碼。
set<MyNum> numset;
對與否,先來看看set的STL中的定義吧,以visual studio 2008為例。
// TEMPLATE CLASS settemplate<class _Kty, class _Pr = less<_Kty>, class _Alloc = allocator<_Kty> > class set : public _Tree<_Tset_traits<_Kty, _Pr, _Alloc, false> > { // ordered red-black tree of key values, unique keyspublic: typedef set<_Kty, _Pr, _Alloc> _Myt; typedef _Tree<_Tset_traits<_Kty, _Pr, _Alloc, false> > _Mybase; typedef _Kty key_type; typedef _Pr key_compare; typedef typename _Mybase::value_compare value_compare; typedef typename _Mybase::allocator_type allocator_type; typedef typename _Mybase::size_type size_type; typedef typename _Mybase::difference_type difference_type; typedef typename _Mybase::pointer pointer; typedef typename _Mybase::const_pointer const_pointer; typedef typename _Mybase::reference reference; typedef typename _Mybase::const_reference const_reference; typedef typename _Mybase::iterator iterator; typedef typename _Mybase::const_iterator const_iterator; typedef typename _Mybase::reverse_iterator reverse_iterator; typedef typename _Mybase::const_reverse_iterator const_reverse_iterator; typedef typename _Mybase::value_type value_type;
特別注意這一行,class _Pr = less<_Kty>, set中是通過less的函數來做比較的,用於判定函數是否存在,其原型為key_comp。key_comp接受2個物體,這2個物體必須為set中的對像,之後通過weak ordering和reflexive來判定物體是否已經存在。f(x,y ) && f(x,y) 同時為false的時候,則物體不存在,便插入。
struct MyNumComp {bool operator()(const MyNum &lhs, const MyNum &rhs) {return (lhs.m_lhs < rhs.m_lhs);}};
我實現了一個key_comp的方函數,但只是比較第一個數而不是兩個全部比較,想想為甚麼呢?
拿這個數組為例:int arr[7] = {5,2,1,4,7,3,6};
我給定一個數為7,那麼應該輸出的是
5,2
1,6
4,3
則,(5,2)-(2,5)必定成對出現,我在後面的算法中,插入的順序也是以小的數在前(2,5),我要的只是一對(2,5),比較的時候會自反比較:(2,5)-(5,2)。
那麼如果在key_comp中,兩個數都做less比較的話,則邏輯方面說不通。舉個例子:set中已存在(2,5)。
當我插入(3,5)的時候,就不行了。
下面說說主算法的思路,原來的算法雖可以找出所有的數對,但只是對有序數組有效,對於無序的數組,用hash_map來做吧。
想想看,如果兩個數的和等於一個數,那麼我們可以用K - 其中一個數,得到是另一個數,反之亦然。第二,把所有的數存入hash_map,在把那個K-數組中的數存入hash_map,如果有數對,那麼他們的value必定是2。對於4+4 =8, 8+8=16這種,value為4。 {1,2,4,4,8,6}
先生成hash_map,如果差小於零就沒有必要放了。:
for (int i = 0; i < ARRNUM; i++) {int val = sum - arr[i];if (val > 0)hmap[sum - arr[i]]++;hmap[arr[i]]++;}
然後遍歷hash_map,找出數對放入 set中。注意:set插入可是以key_comp為順序的喔,你也可以定義greater。
hash_map<int,int>::iterator itr;for (itr = hmap.begin(); itr != hmap.end(); itr++) {// such as 4+4 = 8, 6+6 = 12if ( itr->first != 0 && itr->first == sum / 2 && itr->second == 4) {numset.insert(MyNum(itr->first,itr->first));}if (itr->second == 2 && itr->first != sum / 2) {int val1 = itr->first;int val2 = sum - itr->first;if (val1 > val2)numset.insert(MyNum(val2,val1));elsenumset.insert(MyNum(val1,val2));}}
第一個判斷處理4+4,8+8這種情況,第二個處理只有一個4,8但和為8,16這種情況。Whatever,set的插入總是以小的數在前。
下面看看完整的代碼:
#define ARRNUM 1000struct MyNum {int m_lhs;int m_rhs;MyNum(int v1, int v2) {m_lhs = v1;m_rhs = v2;}};struct MyNumComp {bool operator()(const MyNum &lhs, const MyNum &rhs) {return (lhs.m_lhs < rhs.m_lhs);}};int main() {int arr[ARRNUM]; for (int i = 0; i < 500; i++) arr[i] = i+1; for (int i = 500; i < ARRNUM; i++) arr[i] = ARRNUM - i + 500; typedef set<MyNum,MyNumComp> Mysetnum;Mysetnum numset;hash_map<int,int> hmap;int sum = 516;DWORD dwStart = GetTickCount();for (int i = 0; i < ARRNUM; i++) {int val = sum - arr[i];if (val > 0)hmap[sum - arr[i]]++;hmap[arr[i]]++;}hash_map<int,int>::iterator itr;for (itr = hmap.begin(); itr != hmap.end(); itr++) {// such as 4+4 = 8, 6+6 = 12if ( itr->first != 0 && itr->first == sum / 2 && itr->second == 4) {numset.insert(MyNum(itr->first,itr->first));}if (itr->second == 2 && itr->first != sum / 2) {int val1 = itr->first;int val2 = sum - itr->first;if (val1 > val2)numset.insert(MyNum(val2,val1));elsenumset.insert(MyNum(val1,val2));}}DWORD dwEnd = GetTickCount() - dwStart;cout << "The time is: " << dwEnd / 1000.0f << endl;cin.get();// printcout << "The sum is 516, so..." << endl;Mysetnum::iterator itrSet = numset.begin();while (itrSet != numset.end()) {cout << " (" << itrSet->m_lhs << ", " << itrSet->m_rhs <<") \t";itrSet++;}
時間複雜度為O(2n),空間複雜度O(n),輸出結果如下圖:
如有其他好的算法,可以補充,但本人不喜歡先把無序數組排序,排序也要時間的對吧。這道題一是熟悉基本的算法,二是熟悉STL中的set,怎麼加入自訂義類型,怎麼寫自己的key_comp仿函數。
- 两个数之和等于第三个数 --改進版 。
- 两个数之和等于第三个数
- 人人网2014年笔试题【两个数之和等于第三个数】
- 两个数之和等于目标数
- 数组两个数之和,等于给定数
- 找出一个有序数组中任意2数之和等于给出的第三个数
- 一个数(3000内)等于两个素数之和
- 【c语言】求斐波那契数列的前40个数。特点,第1,2个数为1,从第三个数开始,该数是前面两个数之和
- 解第一个数是1,第二个数是1,第三个数是前两个数之和,求第n个数的值。
- 数组中两个数之和等于某个数字,返回这两个数的下标
- 两个数字之和等于sum
- 两数之和等于x
- 两数之和等于目标值
- 【算法C++】检测数组里是否有两个数之和等于某个数
- C#第三周 任务4 求两个数之和
- 一个无序数组中两个数之和等于给定的值sum
- 给出一个数和一个有序数组,找出该数组中之和等于该数的两个数
- 求两个数之和
- ubuntu下命令(一)
- LDR 、ADR介绍
- BackgroundColorSpan如何赋值为自定义的颜色
- 嵌入式在线(论坛)
- linux内核(linux kernel2.6)编程 视频教程下
- 两个数之和等于第三个数 --改進版 。
- hdu 3416 最短路+最大流
- poj 2104 划分树
- 设计挂了吗?(设计已死? Is Design Dead?)译文
- 做自己的心理调解师
- LATEX TEMPLATE (SPRINGER) (*.BST)
- 你的人生取决于你所遇到的人
- 内存管理有哪几种方式
- 工作建议