1、题目描述
【JZ51】给定一个数组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[0] = A[1] * A[2] * ... * A[n-1],B[n-1] = A[0] * A[1] * ... * A[n-2]
;)
知识点:数组
难度:☆
2、解题思路
根据题目描述,如果可以使用除法,就很简单。但是要求不能使用。
假设:
left[i] = A[0]*...*A[i-1]
right[i] = A[i+1]*...*A[n-1]
所以:
B[i] = left[i] * right[i]
这样就避免使用了除法。但是如果对每个B[i], 0<=i<n,
都这么求,显然时间复杂度太高。
把整个结果画到下面图:
可知:
left[i+1] = A[0]*...A[i-1]*A[i]
right[i+1] = A{i+2]*...*A[n-1]
于是,
left[i+1] = left[i] * A[i]
right[i] = right[i+1] * A[i+1]
所以,可以先把所有的left[i]
求出,right[i]
求出。
3、解题代码
package pers.klb.jzoffer.simple;
/**
* @program: JZoffer
* @description: 构建乘积数组
* @author: Meumax
* @create: 2020-06-17 10:31
**/
public class ArrayProduct {
public int[] multiply(int[] A) {
// 创建数组B
int[] B = new int[A.length];
// 初始化第一个元素为1
B[0] = 1;
// 计算 left
for (int i = 1; i < A.length; i++) {
B[i] = B[i - 1] * A[i - 1];
}
int temp = 1;
// 计算 right 并乘以 left 得到最终的 B
for (int j = A.length - 2; j >= 0; j--) {
temp = temp * A[j + 1];
B[j] = B[j] * temp;
}
return B;
}
}
时间复杂度:O(N)
空间复杂度: O(1)
4、解题心得
虽然这道题的难度为一颗星,而且我看到题目是的第一反应也是写成下面这样:
package pers.klb.jzoffer.simple;
/**
* @program: JZoffer
* @description: 构建乘积数组
* @author: Meumax
* @create: 2020-06-17 10:31
**/
public class ArrayProduct {
public int[] multiply(int[] A) {
int length = A.length;
int[] B = new int[length];
for(int i=0;i<length;i++){
B[i] = mulWithoutIndex(A,i);
}
return B;
}
public int mulWithoutIndex(int[] A,int index){
int result = 1;
for(int i = 0;i<A.length;i++){
if(i == index){
continue;
}else{
result *= A[i];
}
}
return result;
}
}
思路极其简单,潜意识就蹦出来了:对于B的每一个元素B[i]
,计算乘积的时候只需要把对应位置的A[i]
跳过去就行了。
后来一分析自己的这个写法,问题就出在时间复杂度上,自己没有意识到其实自己写出了双层嵌套的for循环,也就是说时间复杂度达到了O(N²),这是不行的,因为有优化空间。