構建乘積數組--java

題目:給定一個數組A[0,1,...,n-1],請構建一個數組B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]。不能使用除法。算法

解析:這道題,直觀的解法是:設置一個循環(由0到n-1),計算B[i]時,忽略掉A[i]項,把數組A中的其餘項所有相乘,即獲得B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]。這樣,一次循環事後,就能夠在沒有除法的條件下,獲得數組B中全部的值。那麼,這種解法的時間複雜度和空間複雜度是多少呢?時間複雜度:因爲循環由0~n-1,即o(n),在每次循環中,要執行n-1次乘法運算,因此這種解法的時間複雜度爲o(n)*o(n-1)=o(n2);空間複雜度爲o(1)。數組

  顯然,上面這種解法的時間複雜度較高,那麼有沒有o(n)的解法呢?咱們不妨分析一下上面這種解法的問題,從而找到能夠優化的突破口。上面的複雜度由兩部分組成,第一部分:循環由0~n-1,顯然咱們須要計算每個B[i],無論怎樣,咱們都沒辦法去掉這樣的基本循環,也就是說這一部分帶來了時間複雜度o(n)不能再進行優化;第二部分:每一次計算B[i]都須要進行n-1次乘法,也便是須要計算n次n-1個數相乘,細心的人能夠發現,這裏面有不少的乘法是重複的,正是因爲這部分重複的乘法計算形成咱們的時間複雜度很高。那麼,有沒有辦法只計算一次這樣的n-1個數相乘呢?咱們能夠定義兩個中間數組來存儲已經計算過得乘法結果,這樣,在進行下一個B[i]計算時,咱們只須要完成一次乘法就能夠獲得B[i]的結果了。這樣,時間複雜度就變成了o(1),整個算法時間複雜度就降成了o(n)。具體分析思路以下:優化

        首先,咱們能夠將數組B表示成矩陣的形式以下:spa

 B[0]  1 A[1] A[2] ... A[n-2] A[n-1]
B[1] A[0] 1 A[2] ... A[n-2] A[n-1]
B[2] A[0] A[1] 1 ... A[n-2] A[n-1]
... ... ... ... 1 ... ...
B[n-2] A[0] A[1] A[2] ... 1 A[n-1]
B[n-1] A[0] A[1] A[2] ... A[n-2] 1

如上圖所示,矩陣的每一行表明數組B的一個元素,從上往下,依次是B[0],B[1],...B[n-2],B[n-1]。那麼,咱們能夠將每個B[i]當作兩部分,分別用C[i]和D[i]表示。其中C[i] = A[0]*A[1]*...*A[i-1],D[i] = A[i+1]*...*A[n-2]*A[n-1],這樣,B[i]=C[i]*1*D[i]。也就是說,咱們能夠每次更新數組C[i]和D[i],即C[i]=C[i-1]*A[i-1]和D[i]=D[i+1]*A[i+1](須要說明的是,這裏C[i]的更新是按照從前日後,而D[i]則是從後往前),從而爲咱們節省了大量的重複的乘法計算,使得時間複雜度降爲o(n)。code

int[] multiply(int[] A){
    if(A==null||A.length<=0)//邊界條件,最好附帶上
            return null;
    int n = A.length;
    int[] B = new int[n];
    B[0]=1;
    /*更新C[i],這裏咱們不另外定義數組,直接將C[i]的計算結果存儲在B[i]中,
       這樣,再將D[i]的結果直接乘以B[i](此時B[i]等於C[i]),就獲得了最終
       的B[i],顯然爲咱們又節省了很多空間存儲。
    */
    for(int i=1;i<n;i++){
            B[i]=B[i-1]*A[i-1];
    }
    int temp =1;
    //更新D[i],這裏要從n-2開始,由於B[n-1]已獲得最終結果
    for(int j=n-2;j>=0;j--){
            temp*=A[j+1];
            B[j]*=temp;
    }
   return B; }

  顯然,上述解法的時間複雜度爲:2*o(n)*2=o(n)。blog

相關文章
相關標籤/搜索