• 【LeetCode】【剑指offer】【构建乘积数组】


    剑指 Offer 66. 构建乘积数组

    给定一个数组 A[0,1,…,n-1],请构建一个数组 B[0,1,…,n-1],其中 B[i] 的值是数组 A 中除了下标 i 以外的元素的积, 即 B[i]=A[0]×A[1]×…×A[i-1]×A[i+1]×…×A[n-1]。不能使用除法。

    示例:

    输入: [1,2,3,4,5]
    输出: [120,60,40,30,24]
     

    提示:

    所有元素乘积之和不会溢出 32 位整数
    a.length <= 100000

    来源:力扣(LeetCode)
    链接:https://leetcode.cn/problems/gou-jian-cheng-ji-shu-zu-lcof
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

     

    如果是使用下面嵌套遍历两次的话,时间复杂度就会变成O(N^2),会超时

    1. class Solution {
    2. public:
    3. vector<int> constructArr(vector<int>& a) {
    4. vector<int> result;
    5. for(int i=0;isize();i++)
    6. {
    7. int tmp=1;
    8. for(int j=0;jsize();j++)
    9. {
    10. if(j==i)
    11. {
    12. continue;
    13. }
    14. else
    15. {
    16. tmp*=a[j];
    17. }
    18. }
    19. result.push_back(tmp);
    20. }
    21. return result;
    22. }
    23. };

     

     

     我们转换一下思路,求除了当前位置的元素的相乘结果就是求当前元素左侧的所有元素的相乘结果乘上当前元素右侧的所有元素的相乘结果

    1   

    2   

    3   

    4   

    5   

    当前元素的左边的所有数据相乘

    1     

    1     

    2     

    6     

    24   

    当前元素的右边的所有数据相乘

    120

    60  

    20  

    5    

    1    

    上面的两张表格对应位置的元素相乘

    120

    60  

    40 

    30  

    24 

     也就得到了我们的结果

    1. class Solution {
    2. public:
    3. vector<int> constructArr(vector<int>& a) {
    4. int size=a.size();
    5. if(size==0)
    6. {
    7. return a;
    8. }
    9. vector<int> left(size,0);
    10. //第一个位的初始值赋值为1
    11. left[0]=1;
    12. vector<int> right(size,0);
    13. //最后一个位的初始值赋值为1
    14. right[size-1]=1;
    15. vector<int> result;
    16. //将当前位左侧的元素全部都相乘,计算出结果
    17. for(int i=1;i
    18. {
    19. left[i]=a[i-1]*left[i-1];
    20. }
    21. //将当前位右侧的元素全部都相乘,计算出结果
    22. for(int i=size-2;i>=0;i--)
    23. {
    24. right[i]=a[i+1]*right[i+1];
    25. }
    26. //我们的结果集就是当前元素的左侧元素乘上右侧的元素
    27. for(int i=0;i
    28. {
    29. result.push_back(left[i]*right[i]);
    30. }
    31. return result;
    32. }
    33. };

    对于上面那种方法我们可以进行优化,采用双指针的方式从左右两边同时遍历,右指针所存储的是当前元素右边的所有元素的相乘的结果,左指针所存储的是当前元素左侧所有的元素相乘的结果。

    初始情况 

    1

    2

    3

    4

    5

    结果数组

    1

    1

    1

    1

    1

     left=1,right=1


    遍历第一遍

    1

    2

    3

    4

    5

    结果数组

    1

    1

    1

    1

    1

    left=1,right=5


    遍历第二遍

    1

    2

    3

    4

    5

    结果数组

    1

    1

    1

    5

    1

     left=2,right=20


    遍历第三遍

    1

    2

    3

    4

    5

    结果数组

    1

    1

    40

    5

    1

    left=6,right=60 


    遍历第四遍

    1

    2

    3

    4

    5

    结果数组

    1

    60

    40

    30

    1

     left=24,right=120


    遍历第五遍

    1

    2

    3

    4

    5

    结果数组

    120

    60

    40

    30

    24

     也就是得到了我们的最终结果

    1. class Solution {
    2. public:
    3. vector<int> constructArr(vector<int>& a) {
    4. int size=a.size();
    5. vector<int> result(size,1);
    6. //我们的左指针存储的是当前元素左侧的所有元素的相乘结果
    7. int left=1;
    8. //我们的右指针存储的是当前元素右侧的所有元素的相乘结果
    9. int right=1;
    10. for(int i=0;i
    11. {
    12. //从左向右乘上左指针中的数据
    13. result[i]*=left;
    14. //从右向左乘上右指针中的数据
    15. result[size-i-1]*=right;
    16. //更新左右指针
    17. left*=a[i];
    18. right*=a[size-i-1];
    19. }
    20. return result;
    21. }
    22. };

  • 相关阅读:
    aspnetcore 使用serilog日志
    tortoisegit 教程
    FFmpeg入门详解之23:视频转码原理
    四、图片特效
    基于飞书通讯录同步构建本地LDAP服务,打通各应用系统间的组织架构和账号信息
    Golang区块链钱包
    vue与react,angular的区别
    纸牌游戏新版小猫钓鱼设计制作
    oak深度相机入门教程-人体姿态估计
    五、Express
  • 原文地址:https://blog.csdn.net/weixin_62684026/article/details/126479974