用C++實現兩個元素相同但順序不同的等長陣列的正確匹配
《程式設計師面試寶典》第五版第96頁題目如下:
有兩等長陣列A,B,所含元素相同,但順序不同,只能取得A陣列某值和B陣列某值進行比較,比較結果為大於,小於,等於,但是不能取得同一陣列A或者B中兩個數進行比較,也不能取得某陣列中的某個值。寫一個演算法實現正確匹配(即A陣列中某值與B陣列中某值等值)。
最簡單的方法: 迴圈加判斷,複雜度O(n^2) 程式碼如下:
#include <iostream> using namespace std; void matching(int a[],int b[],int k) { int i = 0; while(i <= k) { int j = 0; while(j <= k) { if(a[i] == b[j]) { cout << "(" << i <<"," << j <<") "; break; } j++; } i++; } cout << endl; } int main() { int a[10] = {1,2,3,4,5,6,7,8,9,10}; int b[10] = {10,6,4,5,1,8,7,9,3,2}; int k = sizeof(a)/sizeof(int); matching(a,b,k); return 0; }
一種優化方法: 利用二分法的思想,先取A0,與B0Bn-1比較,比較結果計入一個結構陣列C,結構為:{某數在B中的位置,標記,某數在A中的位置}。其中“標記”可為:大於,小於,等於。“某數在A/B中的位置”:0n-1,為相應位置。注:第一次比較後,C中元素都為{某數在B中的位置,標記,A0}格式。 取A1,由C可知B中與A0大小相同的數,與其比較。若A2大,則與B中比A0大的值比較。將比較結果替換計入結構陣列C。若A2小亦同理。 執行至完畢。 程式碼如下:
#define N 10 typedef struct { int loc_b; int flag;//-1,0,1分別表示b[loc_b]<,=,>a[loc_a] int loc_a; }C; C c[N]; int a[N]; int b[N]; //利用快排的思想和二分查詢的思想對陣列進行比較。利用a[0]初始化陣列c,其中陣列前半部分表示b[j]<a[0],後面部分表示b[j]>a[0].同時記錄k,使得b[k]==a[0],以後對a陣列進行比較時均與b[k]進行比較,(因為不讓同陣列之間進行比較). void _match() { int head = 0; int tail = N - 1; int i, j, k; i = rand() % N; //初始化賦值 for (j = 0;j<N;j++) {//類似與按照a[i]的值對b進行快排 if (b[j]>a[i]) {//從後向前插入到c c[tail].flag = 1; c[tail].loc_a = i; c[tail].loc_b = j; tail--; continue; } if (b[j]<a[i]) {//從前向後插入到c c[head].flag = -1; c[head].loc_a = i; c[head].loc_b = j; head++; continue; } if (b[j] == a[i]) { k = j;//記錄相等時候的位置 } } c[head].flag = 0; c[head].loc_a = i; c[head].loc_b = k; //endfor for (i = 0;i<N;i++) { if (a[i]<b[k]) {//a[i]小於b[k]時候,從c的前面進行比較 for (j = 0;j<head;j++) { if (b[c[j].loc_b] == a[i]) { c[j].flag = 0; c[j].loc_a = i; break; } } } else if (a[i]>b[k]) {//從c的後面比較 for (j = head + 1;j<N;j++) { if (b[c[j].loc_b] == a[i]) { c[j].flag = 0; c[j].loc_a = i; break; } } } } } int main() { int i = 0; for (i = 0;i<N;i++) { a[i] = i; b[i] = N - i - 1; } for (i = 0;i<sizeof(a) / sizeof(a[0]);i++) printf("%d ", a[i]); printf("\n"); for (i = 0;i<sizeof(b) / sizeof(b[0]);i++) printf("%d ", b[i]); printf("\n"); _match(); for (i = 0;i<N;i++) { cout << "b[" << c[i].loc_b << "] match a[" << c[i].loc_a << "]" << endl; } system("pause"); return 0; }
進一步優化: 利用快速排序和二分法的思想。 1)在A陣列中隨機選取一個數,(根據題意,我們並不知道這個值的確定值是多少)比如說 A[i] ,然後和B 陣列中進行比較,根據你的資料結構,將B陣列每個數與A[i]進行比較,若比 A[i] 大的按照從後向前儲存,比 A[i] 小的從前向後儲存,要是等於A[i] ,就記錄下來 這個值在B的位置 j,繼續比較,直到B中陣列全部比較完成,然後再把這個相等的b[j] 插入空餘的那個中間位置上。 2) 然後再從A 陣列中取出數A[k]{k=0~n}與B[j](這個B[j] 就是A [i],因為同一陣列中不能比較大小,只能採用這種方式)比較,若比B[j]大,那麼從結構C中 A[i] 後面的比較,若比B[j]小,就從結構C中 A[i] 前面的比較,直到找到相等,然後更新結構陣列C 中與這個相等相應值。(注意,在這裡,只更新相等的那個數值的 “標記”,“某數在A中的位置”,其它與A[k]不相同,或大,或小的情況下,不更新,即還保持A[i] 的比較結果,以利於繼續比較) 3)重複步驟 2,繼續取A陣列 剩下的值,仍然與那個 B[j]比較,這樣逐步更新結構陣列C ,直到A陣列全部取出比較完,那麼這個程式也就完成了相應的功能。 隨機選擇A[i],要是選擇好,可以大大降低比較次數。