28)給定一數組a[N],我們希望構造數組b [N],其中b[j]=a[0]*a[1]…a[N-1] / a[j],在構造過程中,不允許使用除法:
要求O(1)空間複雜度和O(n)的時間複雜度;
除遍曆計數器與a[N] b[N]外,不可使用新的變數(包括棧臨時變數、堆空間和全域靜態變數等);
實現程式(主流程式設計語言任選)實現並簡單描述。
先忽略題目所給的任何限制,天馬行空想象一下,能想象到什麼解法?
1.最簡單的辦法,將a[0]到a[N-1]全乘起來,再遍曆數組,依次除以a[j]即可,這是最簡單的辦法,但是,不允許使用除法,此法不可行.
2.既然不能使用除法,我們可以換一種思維方式:先將a[j]左邊的數全乘一遍,a[j]右邊的數全乘一遍,二者再乘起來,就可以避免除法,得到了a[j]的值.這樣子,顯然要求得每一個a[i]都需要遍曆一遍數組,時間複雜度為o(n),求完所有的a[0]到a[N-1],時間複雜度為o(n^2).不符合題意.但是,這個辦法給我們提供了一種可能性,那就是,能不能在二層嵌套迴圈中整合成一層嵌套迴圈?這個問題暫時不得而知,但是,我們可以知道的是,我們可以實現這個o(n^2)的方法,先實現出來再看看接下來能不能降低時間複雜性.
o(n^2)時間複度性的代碼:
void ConstructArray(int* A,int* B,int N){for(int i=0;i<N;++i){B[i]=1;for(int j=0;j<N;++j){if(j != i){B[i]=B[i]*A[j];}}}}
即: | 為分割線.
表:1-1
A[0]=1|*A[1]*A[2]*........*A[N-1]
A[1]=A[0]*|*A[2]*A[3].......A[N-1]
A[2]=A[0]*A[1]*|*A[3]*......A[N-1]
......
A[j]=A[0*A[1]*...A[j-1]|A[j+1]*A[j+2]*...A[N-1]
上面的代碼實現思路是這樣子的:將問題分為兩部分:對於A[0],A[1].....到A[N-1]的每一個A[i],通過一遍的迴圈遍曆數組得出結果.這樣子就形
成二層嵌套.
現在,我們需要換一個角度想,能不能將分割線|左右兩邊的結果全算出來儲存在一個數組中,然後,兩個數組對應相乘就可以解決問題了.中間,我們不需要兩個暫時數組,可以利用B[N]數組的特點來完成這種累積的過程.
void ConstructArray(int* A,int* B,int N){if(!A || !B) return ;B[0]=1;for(int i=0;i<=N-2;++i){B[i+1]=B[i]*A[i];//對比表:1-1容易知道,構造分割線左邊部分}//上面已經建立了一個金字塔式的左分割線部分,現在自底向上重複上面的操作就能建立右分割線部分for(int i=N-1;i>=1;--i){B[i]=B[i]*B[0];B[0]=B[0]*A[i];}}
總結:
1題目要求比較苛刻,思維方式是利用B[i]構造左邊金字塔型的數組,再構造右邊的金字塔型.中間的轉換比較巧妙.