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 ...