剑指offer面试题66(java版):构建乘积数组

welcome to my blog

剑指offer面试题66(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]。不能使用除法

思路

  • 一定要自己写出通式,立马就明了了!
  • B可以用一个矩阵表示
    • 写一写可以发现B0 = D0, B1=C1D1, B2=C2D2, …,B(n-2)=C(n-2)D(n-2), B(n-1)=C(n-1), B0和B(n-1)仅用C或者D就能表示,为了格式统一,不妨设C0=D(n-1)=1
  • 总结一下
    • Bi = Ci * Di
    • Ci = A0A1…A(i-1) = C(i-1)A(i-1) 这样的递推式,从索引0开始求,可以重复利用之前的Ci,避免重复运算
    • Di = A(i+1)A(i+2)…A(n-1) = D(i+1)A(i+1) 这样的递推式从n-1往前求
  • 所以只要求出Ci和Di就可以了
第三次做, 这题要细心, 要弄出初始条件和更新公式
class Solution {
    public int[] constructArr(int[] a) {
        int n = a.length;
        if(n==0){
            return new int[]{};
        }
        int[] b = new int[n];
        b[0] = 1;
        for(int i=1; i<n; i++){
            b[i] = b[i-1]*a[i-1];
        }
        int tmp = a[n-1];
        for(int i=n-2; i>=0; i--){
            b[i] *= tmp;
            //
            tmp *= a[i];
        }
        return b;

    }
}
public class Solution {
    public int[] multiply(int[] A) {
        if(A==null || A.length==0)
            return A;
        int[] B = new int[A.length];
        B[0] = 1;
        for(int i=1; i<A.length; i++){
            B[i] = B[i-1]*A[i-1];
        }
        //initialize
        int temp = 1;
        for(int i=A.length-1; i>=0; i--){
            //execute
            B[i] = B[i]*temp;
            //update
            temp = temp * A[i];
        }
        return B;
    }
}
第二次做,画了个矩阵进行观察,Bi由两部分构成,单独看其中一部分,就会发现每行都是上一行多乘一个元素的结果,这说明仅看其中一部分时, 当前行可以由上一行得到, 经过一次遍历就可以得到所有行的结果; 再看另一部分,行与行之间也满足这样的关系, 再遍历一遍数组就可以得到最终的结果
  • 时间复杂度O(N)
  • 画矩阵后发现了每行比上一行多一个, 像一个阶梯状, 看着挺舒服
import java.util.ArrayList;
public class Solution {
    public int[] multiply(int[] A) {
        if(A==null || A.length==0)
            return A;
        int[] B = new int[A.length];
        B[0] = 1;
        for(int i=1; i<A.length; i++){
            B[i] = A[i-1]*B[i-1];
        }
        int temp = 1;
        for(int i=B.length-1; i>=0; i--){
            B[i] = B[i]*temp;
            temp = temp*A[i];
        }
        return B;
    }
}
创建了两个数组保存上三角和下三角的各个值
public class Solution {
    public int[] multiply(int[] A) {
        //input check
        //execute
        int[] B = new int[A.length];
        int[] C = new int[A.length];
        int[] D = new int[A.length];
        C[0]=D[A.length-1]=1;
        for(int i=1; i<A.length; i++){
            // 使用C和D的递推式求C和D的各个值,避免重复运算
            C[i] = C[i-1] * A[i-1];
            D[A.length-1-i] = D[A.length - i] * A[A.length - i];
        }
        for(int i=0; i<A.length; i++)
            B[i] = C[i] * D[i];
        return B;
    }
}
空间开销更小的方式(计算上三角和下三角没有创建新数组)
public class Solution {
    public int[] multiply(int[] A) {
        //input check
        //execute
        int[] B = new int[A.length];
        //计算下三角
        B[0] = 1;
        for(int i=1; i<A.length; i++){
            B[i] = B[i-1]*A[i-1]; // 下三角的递推式
        }
        //计算上三角
        int temp =1; // 使用temp存储各次循环中的上三角结果
        for(int i=A.length-2; i>=0; i--){
            temp = A[i+1] * temp; //上三角的递推式
            B[i] = B[i] * temp;
        }
        return B;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值