尋找和為定值的兩個數

2021-07-26 19:59:59 字數 2913 閱讀 8125

題目描述

輸入乙個陣列和乙個數字,在陣列中查詢兩個數,使得它們的和正好是輸入的那個數字。

要求時間複雜度是o(n)。如果有多對數字的和等於輸入的數字,輸出任意一對即可。

例如輸入陣列1、2、4、7、11、15和數字15。由於4+11=15,因此輸出4和11。

分析與解法

咱們試著一步一步解決這個問題(注意闡述中數列有序無序的區別):

直接窮舉,從陣列中任意選取兩個數,判定它們的和是否為輸入的那個數字。此舉複雜度為o(n^2)。很顯然,我們要尋找效率更高的解法

題目相當於,對每個a[i],查詢sum-a[i]是否也在原始序列中,每一次要查詢的時間都要花費為o(n),這樣下來,最終找到兩個數還是需要o(n^2)的複雜度。那如何提高查詢判斷的速度呢?

答案是二分查詢,可以將o(n)的查詢時間提高到o(log n),這樣對於n個a[i],都要花logn的時間去查詢相對應的sum-a[i]是否在原始序列中,總的時間複雜度已降為o(n log n),且空間複雜度為o(1)。 (如果有序,直接二分o(n log n),如果無序,先排序後二分,複雜度同樣為o(n log n + n log n)= o(n log n),空間複雜度總為o(1))。

可以繼續優化做到時間o(n)麼?

解法一

根據前面的分析,a[i]在序列中,如果a[i]+a[k]=sum的話,那麼sum-a[i](a[k])也必然在序列中。 舉個例子,如下: 原始序列:

1、 2、 4、 7、11、15

用輸入數字15減一下各個數,得到對應的序列為:

14、13、11、8、4、 0

第乙個陣列以一指標i 從陣列最左端開始向右掃瞄,第二個陣列以一指標j 從陣列最右端開始向左掃瞄,如果第乙個陣列出現了和第二個陣列一樣的數,即a[ i]=a[ j],就找出這倆個數來了。 如上,i,j最終在第乙個,和第二個序列中找到了相同的數4和11,所以符合條件的兩個數,即為4+11=15。 怎麼樣,兩端同時查詢,時間複雜度瞬間縮短到了o(n),但卻同時需要o(n)的空間儲存第二個陣列。

解法二

當題目對時間複雜度要求比較嚴格時,我們可以考慮下用空間換時間,上述解法一即是此思想,此外,構造hash表也是典型的用空間換時間的處理辦法。

即給定乙個數字,根據hash對映查詢另乙個數字是否也在陣列中,只需用o(1)的時間,前提是經過o(n)時間的預處理,和用o(n)的空間構造hash表。

但能否做到在時間複雜度為o(n)的情況下,空間複雜度能進一步降低達到o(1)呢?

解法三

如果陣列是無序的,先排序(n log n),然後用兩個指標i,j,各自指向陣列的首尾兩端,令i=0,j=n-1,然後i++,j–,逐次判斷a[i]+a[j]?=sum,

如果某一刻a[i]+a[j] > sum,則要想辦法讓sum的值減小,所以此刻i不動,j–;

如果某一刻a[i]+a[j] < sum,則要想辦法讓sum的值增大,所以此刻i++,j不動。

所以,陣列無序的時候,時間複雜度最終為o(n log n + n)=o(n log n)。

如果原陣列是有序的,則不需要事先的排序,直接用兩指標分別從頭和尾向中間掃瞄,o(n)搞定,且空間複雜度還是o(1)。

下面,咱們先來實現此思路(這裡假定陣列已經是有序的),**可以如下編寫:

void twosum(int data, unsigned int length, int sum)

else

}} 解法總結

不論原序列是有序還是無序,解決這類題有以下三種辦法:

1、二分(若無序,先排序後二分),時間複雜度總為o(n log n),空間複雜度為o(1);

2、掃瞄一遍x-s[i] 對映到乙個陣列或構造hash表,時間複雜度為o(n),空間複雜度為o(n);

3、兩個指標兩端掃瞄(若無序,先排序後掃瞄),時間複雜度最後為:有序o(n),無序o(n log n + n)=o(n log n),空間複雜度都為o(1)。

所以,要想達到時間o(n),空間o(1)的目標,除非原陣列是有序的(指標掃瞄法),不然,當陣列無序的話,就只能先排序,後指標掃瞄法或二分(時間 o(nlog n),空間o(1)),或對映或hash(時間o(n),空間o(n))。時間或空間,必須犧牲乙個,達到平衡。

綜上,若是陣列有序的情況下,優先考慮兩個指標兩端掃瞄法,以達到最佳的時o(n),空o(1)效應。否則,如果要排序的話,時間複雜度最快當然是只能達到o(n log n),空間o(1)則不在話下。

問題擴充套件

如果在返回找到的兩個數的同時,還要求你返回這兩個數的位置列?

如果需要輸出所有滿足條件的整數對呢?

如果把題目中的要你尋找的兩個數改為「多個數」,或任意個數列?

舉一反三

1、在二元樹中找出和為某一值的所有路徑 輸入乙個整數和一棵二元樹,從樹的根結點開始往下訪問一直到葉結點所經過的所有結點形成一條路徑,然後列印出和與輸入整數相等的所有路徑。 例如輸入整數22和如下二元樹

10 / \

5 12

/ \

4 7則列印出兩條路徑:10, 12和10, 5, 7。 其中,二元樹節點的資料結構定義為:

struct binarytreenode // a node in the binary tree

; 2、有乙個陣列a,設有乙個值n。在陣列中找到兩個元素a[i]和a[j],使得a[i]+a[j]等於n,求出所有滿足以上條件的i和j。

3、3-sum問題

給定乙個整數陣列,判斷能否從中找出3個數a、b、c,使得他們的和為0,如果能,請找出所有滿足和為0個3個數對。

4、4-sum問題

給定乙個整數陣列,判斷能否從中找出4個數a、b、c、d,使得他們的和為0,如果能,請找出所有滿足和為0個4個數對。

尋找和為定值的兩個數

尋找和為定值的兩個數 給定乙個陣列 無序或者有序,兩種情況都要考慮 找出和為m的兩個數。最多時間複雜度能有多少?陣列有序的情況,在時間複雜度上我們就省去了排序的o nlogn 我們使用兩端指標掃瞄法是比較簡單的,時間複雜度為o n 空間複雜度為o 1 如下圖所示 然後,判斷它們指向的值之和sum是否...

尋找和為定值的兩個數

描述 輸入乙個陣列和乙個數字,在陣列中查詢兩個數,使得它們的和正好是輸入的那個數字。要求時間複雜度是o n 如果有多對數字的和等於輸入的數字,輸出任意一對即可。例如輸入陣列1 2 4 7 11 15和數字15。由於4 11 15,因此輸出4和11。分析 如果採取窮舉,複雜度為o n 2 可以換乙個思...

尋找和為定值的兩個數

題目 輸入乙個陣列和乙個數字,在陣列中查詢兩個數,使得它們的和正好是輸入的那個數字。要求時間複雜度是o n 如果有多對數字的和等於輸入的數字,輸出任意一對即可。例如輸入陣列1 2 4 7 11 15和數字15。由於4 11 15,因此輸出4和11。解析 如果陣列是無序的,先排序 n logn 然後用...