算法③:构建乘积数组

算法③:构建乘积数组

​ 题目链接:https://leetcode-cn.com/problems/gou-jian-cheng-ji-shu-zu-lcof/

题目要求:

​ 给定一个数组 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]。不能使用除法。

示例 1:
输入: [1,2,3,4,5]
输出: [120,60,40,30,24]
提示:
所有元素乘积之和不会溢出 32 位整数
a.length <= 100000

解题思路

思路一

本题的难点在于 不能使用除法 ,即需要 只用乘法 生成数组 BB 。

根据题目对 B[i]B[i] 的定义,可列表格,如下图所示:

根据表格的主对角线(全为 11 ),可将表格分为 上三角 和 下三角 两部分。分别迭代计算下三角和上三角两部分的乘积,即可 不使用除法 就获得结果。

在这里插入图片描述

算法流程:
初始化:数组 BB ,其中 B[0] = 1B[0]=1 ;辅助变量 tmp = 1tmp=1 ;
计算 B[i]B[i] 的 下三角 各元素的乘积,直接乘入 B[i]B[i] ;
计算 B[i]B[i] 的 上三角 各元素的乘积,记为 tmptmp ,并乘入 B[i]B[i] ;
返回 BB 。
复杂度分析:
时间复杂度 O(N)O(N) : 其中 NN 为数组长度,两轮遍历数组 aa ,使用 O(N)O(N) 时间。
空间复杂度 O(1)O(1) : 变量 tmptmp 使用常数大小额外空间(数组 bb 作为返回值,不计入复杂度考虑)

参考动图算法解析:

https://leetcode-cn.com/problems/gou-jian-cheng-ji-shu-zu-lcof/solution/mian-shi-ti-66-gou-jian-cheng-ji-shu-zu-biao-ge-fe/

思路二

对称遍历!
建立两个数组:C[n]和D[n]
第一个存放左半部分的值,第二个存放右半部分的值;
因为b的值是把a数组拆成了左右两部分,最后乘积得到的
C[i]表示a数组从第0项乘到i-1项的乘积;
D[i]表示从i+1到n-1项的乘积;两项相乘,就是对B[i]

图解!变成
在这里插入图片描述

找规律:

​ c[n]=c[n-1]*a[n-1]
​ d[n]=d[n+1]a[n+1],

​ 也就是上一次结果a的值,然后两个值相乘,得到b[n]

从上述想法优化:b数组本身可以代表左侧数组c
再用temp变量记录右侧的值,没算出一个值,就和左侧的相乘,也就省去了右侧的数组

class Solution {
    public int[] constructArr(int[] a) {
        if(0==a.length) {
            return new int[0];
        }
        int length=a.length;
        int[] b=new int[length];
        b[0]=1;
        for(int i=1;i<length;i++) {
            b[i]=b[i-1]*a[i-1];
        }
        int temp=1;
        for(int j=length-2;j>=0;j--) {
            temp*=a[j+1];
            b[j]*=temp;
        }
        return b;
    }
}
java解法
class Solution {
    public int[] constructArr(int[] a) {
        int[] res = new int[a.length];
        for (int i = 0, cur = 1; i < a.length; i++) {
            res[i] = cur;   // 先乘左边的数(不包括自己)
            cur *= a[i];
        }
        for (int i = a.length - 1, cur = 1; i >= 0; i--) {
            res[i] *= cur;  // 再乘右边的数(不包括自己)
            cur *= a[i];
        }
        return res;
    }
}
C++解法
class Solution {
public:
    vector<int> constructArr(const vector<int>& A) {
        int n = A.size();
        vector <int> b(n);
        int temp = 1;
        for (int i = 0; i < n; i++){
            b[i] = temp;//如果要累乘的话需要把内容初始化为1
            temp *= A[i];//这样先赋值,在对i进行累乘,可以使a[i]不被乘进去
            //把所有左边的都乘进数组里了,用temp不重复计算!!利用上次的值!!
        }
        temp = 1; //重新清零
        for (int i = n - 1;i >= 0; --i){
            b[i] *= temp;//之前b[]还是个半成品
            temp *= A[i];
        }
        return b;
    }
};
C语言解法
int* constructArr(int* a, int aSize, int* returnSize){
    int *arr = NULL;
    int i, temp;
    if (a == NULL || aSize <= 1) {
        *returnSize = 0;
        return a;
    }
    *returnSize = aSize;
    arr = (int *)malloc(sizeof(int) * aSize);
    arr[0] = 1;

    for (i = 1; i < aSize; i++) {
        arr[i] = arr[i - 1] * a[i - 1];
    }

    temp = 1;
    for (i = aSize - 2; i >= 0; i--) {
        temp *= a[i + 1];
        arr[i] *= temp;
    }

    return arr;
}
Python解法
class Solution:
    def constructArr(self, a: List[int]) -> List[int]:
        n = len(a)
        L, R = [1] * n, [1] * n
        for i in range(1, n):
            L[i] = L[i - 1] * a[i - 1]
        for j in reversed(range(n - 1)):
            R[j] = R[j + 1] * a[j + 1]
        for i in range(n):
            L[i] = L[i] * R[i]
        return L
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MrZhangBaby

请博主喝杯奶茶

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值