演算法練習:兩數之和,演算法兩數之和
題目:給定一個整型數組,是否能找出兩個數使其和為指定的某個值?註:整型數組中不存在相同的數。
一、解題方法
1、暴力破解法(時間複雜度O(n^2) )
這是最容易想到的一種方法,即使用兩層迴圈,從數組裡取出一個數,然後在此數之後部分找出另外一個數,計算兩數之和,判斷是否等於指定值。如下:
//直觀的辦法,使用兩個迴圈bool IsExistSumOfTwoNum( int nArray[], int nCount, int nSum ){bool bRet = false;for ( int i = 0; i < nCount - 1; ++i ){for ( int j = i + 1; j < nCount; ++j ){if ( ( nArray[i] + nArray[j] ) == nSum ){bRet = true;break;}}}return bRet;}
此種方法的的時間複雜度為O(n^2),那麼能否降低此複雜度呢?答案是可以的,請看第二種方法。
2、排序加首尾指標(時間複雜度O(nlogn) )
先對數組進行從小到大的排序,然後設定首尾指標,從首尾兩端開始移動,一次移動一端的指標,直至兩指標相遇或者兩指標指向的數的和為指定的值。
假設兩指標為i,j,其中i < j,如果a[i]、a[j]之和大於指定值,那麼要找的兩個數一定在j的左側,如果a[i]、a[j]之和小於指定值,那麼要找的兩個數一定在i的右側。可用反證法證明此結論的正確性,證明略。
bool IsExistSumOfTwoNum( int nArray[], int nCount, int nSum ){//從小到大排序std::sort( nArray, nArray+nCount, std::less<int>() );//首尾指示int i = 0; int j = nCount - 1;bool bRet = false;while( i < j ){if ( ( nArray[i] + nArray[j] ) == nSum ){bRet = true;break;}else if ( ( nArray[i] + nArray[j] ) > nSum ){--j;}else{++i;}}return bRet;}
此種演算法中,一開始有一個排序,最好的排序的時間複雜度可為O(nlogn),比如堆排序、歸併排序、快速排序。While迴圈至多掃描一遍數組,所以其時間表複雜度為O(n)。由此可得,最終的時間複雜度為O(nlogn)。那麼能否再降低時間複雜度呢?答案還是可以的,但是這時需要一個額外的儲存空間,請看第三種方法。
3、利用雜湊表(時間複雜度O(n) )
將複雜度為O(nlogn)降低至O(n),首先想到的是雜湊表,因為雜湊表的尋找時間複雜度為O(n)。
掃描一遍數組,將其數組各個值儲存至雜湊表中,比如鍵值:<數組值--索引>。然後再次開始從頭掃描數組,檢查指定值與當前值的差值是否在雜湊表中(特殊情況:如果遇到差值為當前值時,那麼不應返回,因為數組中的值是不相同的)。
程式碼實現說明:程式中使用c++標準庫中的set代替雜湊表,因為標準庫中還未收錄雜湊表相關部分。此處若需要兩數的索引資訊,可以考慮使用map。因為set、map內部使用的是紅/黑樹狀結構資料結構,尋找效率高,具體的複雜度,我還沒好好研究,呵呵。希望此處用set代替雜湊表,不要引起誤會,姑且將它理解為尋找複雜度為常數時間的東西吧。
//使用額外的儲存空間bool IsExistSumOfTwoNum( int nArray[], int nCount, int nSum ){//打描一遍數組,將值存放於雜湊表中//(註:此處使用set代替下雜湊表,它內部實現說是紅/黑樹狀結構,還沒仔細研究過,呵)std::set<int> siSetTemp;int i = 0;bool bRet = false;for ( i = 0; i < nCount; ++i ){siSetTemp.insert( nArray[i] );}for ( i = 0; i < nCount; ++i ){std::set<int>::iterator it = siSetTemp.find( nSum - nArray[i] );if ( it != siSetTemp.end() && (nSum != 2 * nArray[i] ) ){bRet = true;break;}}return bRet; }
此種演算法中,雜湊表的尋找是常數時間,所以時間複雜度為O(n),空間複雜度為
O(n),即數組大小O(n)。
二、擴充問題
如果要返回其中所有的可能或者數組裡面存在相同的數,那麼應當怎麼解決呢?相信有了以上的知識,這個解決起來也不難。一個是開闢一個儲存結果的數組,搜尋完整個數組空間;另外一個無非就是讓雜湊表中多存放點資料。
系列文章說明:
1.本系列文章[演算法練習],僅僅是本人學習過程的一個記錄以及自我激勵,沒有什麼說教的意思。如果能給讀者帶來些許知識及感悟,那是我的榮幸。
2.本系列文章是本人學習陳東鋒老師《進軍矽谷,程式員面試揭秘》一書而寫的一些心得體會,文章大多數觀點均來自此書,特此說明!
3.文章之中,難免有諸多的錯誤與不足,歡迎讀者批評指正,謝謝.
作者:山丘兒
轉載請標明出處,謝謝。原文地址:http://blog.csdn.net/s634772208/article/details/46388789