构建乘积数组

1.题目描述

给定一个数组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.具体算法

class Solution {
public:
    vector<int> multiply(const vector<int>& A) {
        int n = A.size();//定义一个n,用来记录数组A的大小
        vector<int> B(n,1);
        vector<int> B1(n,1);
        vector<int> B2(n,1);
        for(int j=1;j<n;j++)
        {
            B1[j] = B1[j-1]*A[j-1];//找出B1[j]与B1[j-1]之间的递推关系
        }
        for(int k=n-2;k>=0;k--)
        {
            B2[k] = B2[k+1]*A[k+1];//找出B2[k]与B2[k-1]之间的递推关系
        }
        for(int p=0;p<n;p++)
        {
            B[p]=B1[p]*B2[p];//用数组B1和B2来表示B
        }
        return B;//返回数组B
    }
};

3.算法推导

可能只看上面的算法会觉得很抽象,那么下面就以举例的形式来将这个抽象的问题具体化,把上面算法所要用到的所有的公式都推导出来:

数组B1用来记录A[0]~A[i-1]的数据之间的乘积,而数组B2用来记录A[i+1] ~A[n-1]的数据之间的乘积。(i为0和n时除外,B[0] = A[1] * A[2] * … * A[n-1],B[n-1] = A[0] * A[1] * … * A[n-2])

假设n为5,A[0]=1,A[1]=2,A[2]=3,A[3]=4,A[4]=5;

B[0]=1 * A[1] * A[2] * A[3] * A[4] =B1[0] * B2[0]=2 * 3 * 4 * 5

B[1]=A[0] * 1 * A[2]* A[3] * A[4] =B1[1] * B2[1]=1 * 3 * 4 * 5

B[2]=A[0] * A[1] * 1 * A[3]* A[4] =B1[2] * B2[2]=1 * 2 * 4 * 5

B[3]=A[0] * A[1] * A[2] * 1* A[4] =B1[3] * B2[3]=1 * 2 * 3 * 5

B[4]=A[0] * A[1] * A[2] * A[3]* 1=B1[4] * B2[4]=1 * 2 * 3 * 4

由上面的式子不难发现:
**B1[j] = B1[j-1]A[j-1]
B2[k] = B2[k+1]A[k+1]

4.算法总结

其实我开始写代码的时候,提交的代码是合格的,但是并不是以上的那个形式,而是如下所示:

class Solution {
public:
    vector<int> multiply(const vector<int>& A) {
        int n = A.size();
        vector<int> B(n,1);
        vector<int> B1(n,1);
        vector<int> B2(n,1);
        B1[1]=A[0];
        for(int j=2;j<n;j++)
        {
            B1[j] = B1[j-1]*A[j-1];
        }
        B2[n-2] = A[n-1];
        for(int k=n-3;k>=0;k--)
        {
            B2[k] = B2[k+1]*A[k+1];
        }
        for(int p=0;p<n;p++)
        {
            B[p]=B1[p]*B2[p];
        }
        return B;
    }
};

差别主要就是如下两行:

B1[1]=A[0];
        for(int j=2;j<n;j++)
        {
            B1[j] = B1[j-1]*A[j-1];
        }
        B2[n-2] = A[n-1];
        for(int k=n-3;k>=0;k--)
        {
            B2[k] = B2[k+1]*A[k+1];
        }

按照数学推导的思路,我刚开始是确定了数组B1和B2的初始推导元素B1[1]和B2[n-2]的值,然后再进行剩下的元素值的推导,但后来反应过来B1[0]和B2[n-1]的值都是1,所以没必要这样单独定义B1[1]和B2[n-2]的值,直接写成如下形式即可:

for(int j=1;j<n;j++)
        {
            B1[j] = B1[j-1]*A[j-1];//找出B1[j]与B1[j-1]之间的递推关系
        }
        for(int k=n-2;k>=0;k--)
        {
            B2[k] = B2[k+1]*A[k+1];//找出B2[k]与B2[k-1]之间的递推关系
        }

这两种写法虽然在复杂度和方法思路上都没有太大的区别,但是修改之后的代码就是显得整齐和规整,而且思路和逻辑上更加完善,有时候一个算法关系到逻辑推导的时候,确实应该多检查检查。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值