演算法練習:兩數之和
題目:給定一個整型陣列,是否能找出兩個數使其和為指定的某個值?注:整型陣列中不存在相同的數。
一、解題方法
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