題目:
已知一個包含N個元素的數組A[N],試求出這樣一個數組OUTPUT[N],其中OUTPUT[I]的值為數組A中除了A[i]的其他所有元素的乘積。注意,不能使用除法。時間複雜度必須為O(N)。
例如OUTPUT[0]的值為A[1]*A[2]...A[N], OUTPUT[1]的值為A[0]*A[2]...A[N]。
假定數組A={4, 3, 2, 1, 2},則OUTPUT={12, 16, 24, 48, 24}。
分析:
初看此題,覺得很無聊,這個題目貌似沒有什麼意義。要是可以用除法,直接OUTPUT[I]=A[0]*A[1]...A[N]/A[i]。
但是不能用除法,而且時間複雜度為O(N),確實一時還難以想到好的解法。如果使用暴力方法,每次求OUTPUT[I]都暴力計算一遍,那麼時間複雜度為O(N^2),達不到O(N)的要求。
我們可以定義一個數組B,其中元素B[i]的值為A[0]到A[i]的乘積,即B[i]=A[0]*A[1]...A[i]。假如A = {4, 3, 2, 1, 2},則B = {4, 12, 24, 24, 48}。然後從右向左掃描數組A,並使用一個變數product記錄從右向左掃描到當前位置的乘積。從而OUTPUT[i]=B[i-1]*product.
上面的方法採用O(N)的時間和O(N)的空間,那麼是否還有更好的辦法呢?是否能省去這O(N)的空間呢?
確實是的,這O(N)的空間確實可以省去。我們使用2個變數就可以滿足要求。使用變數left儲存從左向右掃描數組A的乘積,使用變數right儲存從右向左掃描數組A的乘積。
代碼:
void array_multiplication(int A[], int OUTPUT[], int n) { int left = 1; int right = 1; for (int i = 0; i < n; i++) OUTPUT[i] = 1; for (int i = 0; i < n; i++) { OUTPUT[i] *= left; OUTPUT[n - 1 - i] *= right; left *= A[i]; right *= A[n - 1 - i]; }}