快速尋找滿足條件的兩個數

2022-05-28 22:06:13 字數 3480 閱讀 4388

2012-04-18 16:41

2.12快速尋找滿足條件的兩個數---程式設計師程式設計藝術之五

第一節、尋找滿足條件的兩個數

第14題(陣列):

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

要求時間複雜度是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(logn),這樣對於n個a[i],都要花logn的時間去查詢相對應的sum-a[i]是否在原始序列中,總的時間複雜度已降為o(n*logn),且空間複雜度為o(1)。(如果有序,直接二分o(n*logn),如果無序,先排序後二分,複雜度同樣為o(n*logn+n*logn)=o(n*logn),空間總為o(1))。

有沒有更好的辦法列?咱們可以依據上述思路2的思想,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)的空間儲存第二個陣列(@飛羽:要達到o(n)的複雜度,第乙個陣列以一指標i 從陣列最左端開始向右掃瞄,第二個陣列以一指標j 從陣列最右端開始向左掃瞄,首先初始i指向元素1,j指向元素0,誰指的元素小,誰先移動,由於1(i)>0(j),所以i不動,j向左移動。然後j移動到元素4發現大於元素1,故而停止移動j,開始移動i,直到i指向4,這時,i指向的元素與j指向的元素相等,故而判斷4是滿足條件的第乙個數;然後同時移動i,j再進行判斷,直到它們到達邊界)。

當然,你還可以構造hash表,正如程式設計之美上的所述,給定乙個數字,根據hash對映查詢另乙個數字是否也在陣列中,只需用o(1)的時間,這樣的話,總體的演算法通上述思路3 一樣,也能降到o(n),但有個缺陷,就是構造hash額外增加了o(n)的空間,此點同上述思路 3。不過,空間換時間,仍不失為在時間要求較嚴格的情況下的一種好辦法。

如果陣列是無序的,先排序(n*logn),然後用兩個指標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]

總結

public static int i = -1;public static int j = -1;void findsum(int arr,n)

}第二節、尋找滿足條件的多個數

第21題(陣列)

2023年中興面試題

程式設計求解:

輸入兩個整數 n 和 m,從數列1,2,3.......n 中隨意取幾個數,

使其和等於 m ,要求將其中所有的可能組合列出來。

#include

#include

using namespace std;  

listlist1;  

void find_factor(int sum, int n)   

list1.push_front(n);      //典型的01揹包問題  

find_factor(sum-n, n-1);   //放n,n-1個數填滿sum-n  

list1.pop_front();  

find_factor(sum, n-1);     //不放n,n-1個數填滿sum   

}  int main()  

題目的大概意思是:快速找出在乙個陣列內的兩個數,讓這兩個數之和等於乙個給定的值。書中給出的解法三覺得應該是(nlogn)複雜度中比較快的,但這種解法為什麼完備還要仔細推導一下才知道。因為是找兩個數之和,解法二還可以再優化。排序後可以把陣列分成兩段,以和的一半作為分割點,這樣就在二分查詢時只需找出前半部分的sum-arr[i]是否在後半部分中。我用slt的binary_search實現了一下,但是此法由於排序,只能返回具體的解,如果返回解在原陣列中的位置,那要複雜得多。

[cpp]view plain

copy

//給定條件為sum()=10  

#include

usingnamespacestd;  

#include

#include

constintmaxn=1000;  

intsolv=0;  

classlist  

21.     //獲得分割點  

22.voidgetcutpoint()  

23.       

33.         }  

34.     }  

35.boolsearch ( )  

36.       

47.         }  

48.returnfalse;  

49.     }  

50. };  

51.intmain()  

52. ;  

54.     list list1(a,7);  

55.     list1.getcutpoint();  

56.       

57.if(list1.search())  

58.       

61.else

62.       

65.     system("pause");  

66.return1;  

67. }  

快速尋找滿足條件的兩個數

快速尋找滿足條件的兩個數,讓這兩個數字之和等於乙個給定的數字 快速尋找滿足條件的兩個數,讓這兩個數字之和等於乙個給定的數字 public class searchtwonum quicksort.quicksort a 假設sum 9 int sum 9 設定兩個指標 int low 0,high ...

快速尋找滿足條件的兩個數(程式設計之美)

快速找出乙個陣列中的兩個數,讓此兩個數之和等於乙個給定的數。如 5 6 1 4 7 9 8 中找出兩個數之和等於10的數 程式設計之美之美p177有詳細解答過程,思路是先排序 o nlog n 然後儲存兩個指標beg end,初始指向頭部和尾部,如過 beg end sum,則返回 如果 beg e...

程式設計之美 快速尋找滿足條件的兩個數

能否快速找出乙個陣列中的兩個數字,讓這兩個數字之和等於乙個給定的值,為了簡化起見,我們假設這個陣列中肯定存在至少一組符合要求的解。法一 最直接的方法就是,窮舉法,複雜度為o n 2 法二 利用sum減去a i 再查詢sum a i 是否在陣列裡,這時候就變成查詢了,可利用二分查詢 排序的複雜度為o ...