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;
}
}