前后缀算法,力扣238. 除自身以外数组的乘积,2906. 构造乘积矩阵

前后缀算法,力扣238. 除自身以外数组的乘积,2906. 构造乘积矩阵

一,除自身以外数组的乘积

力扣链接
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。

题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。

请 不要使用除法,且在 O(n) 时间复杂度内完成此题。

示例 1:

输入: nums = [1,2,3,4]
输出: [24,12,8,6]
示例 2:

输入: nums = [-1,1,0,-3,3]
输出: [0,0,9,0,0]
提示:

2 <= nums.length <= 105
-30 <= nums[i] <= 30
保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内


如果暴力解法, 以[1,2,3,4]为例
从第一个数开始,需要进行2次乘法,2*3*4
然后第二个数,需要1*3*4
第三个数,需要1*2*4
第四个数,需要1*2*3
显然,时间复杂度是O(n2)
太复杂了
思考:

从第一个数开始,需要进行2次乘法,2*3*4
然后第二个数,需要1*3*4

两个都算了3*4,如果暴力解法,进行了重复运算,所以是不是可以用一个缓存区来记录下3*4 的值呢?这个思想其实和 暴力递归优化到带缓存表的递归 思想非常相似
一维动态规划链接


源码:

class Solution {
        public int[] productExceptSelf(int[] nums){
        int[] left=new int[nums.length];
        int[] right=new int[nums.length];
        left[0]=1;
        right[nums.length-1]=1;
        for(int i=1;i<=left.length-1;i++){
            left[i]=left[i-1]*nums[i-1];
        }
        for(int i=right.length-2;i>=0;i--){
            right[i]=right[i+1]*nums[i+1];
        }
        for(int i=0;i<=nums.length-1;i++){
            nums[i]=left[i]*right[i];
        }
        return nums;
    }
}

left[i]的意思就是:不包括i,i位置左边的数的乘积(left数组就是前缀积)
这一步:
left[i]=left[i-1]*nums[i-1];就是在更新left数组,利用left[i-1]就不用进行重复运算了
在这里插入图片描述
right数组同理。
下面这步就是

for(int i=0;i<=nums.length-1;i++){
            nums[i]=left[i]*right[i];
        }

把除了i位置的所有数相乘,左边的乘以右边的
在这里插入图片描述

二,构造乘积矩阵

力扣链接
给你一个下标从 0 开始、大小为 n * m 的二维整数矩阵 grid ,定义一个下标从 0 开始、大小为 n * m 的的二维矩阵 p。如果满足以下条件,则称 p 为 grid 的 乘积矩阵 :

对于每个元素 p[i][j] ,它的值等于除了 grid[i][j] 外所有元素的乘积。乘积对 12345 取余数。
返回 grid 的乘积矩阵。

示例 1:

输入:grid = [[1,2],[3,4]]
输出:[[24,12],[8,6]]
解释:p[0][0] = grid[0][1] * grid[1][0] * grid[1][1] = 2 * 3 * 4 = 24
p[0][1] = grid[0][0] * grid[1][0] * grid[1][1] = 1 * 3 * 4 = 12
p[1][0] = grid[0][0] * grid[0][1] * grid[1][1] = 1 * 2 * 4 = 8
p[1][1] = grid[0][0] * grid[0][1] * grid[1][0] = 1 * 2 * 3 = 6
所以答案是 [[24,12],[8,6]] 。
示例 2:

输入:grid = [[12345],[2],[1]]
输出:[[2],[0],[0]]
解释:p[0][0] = grid[0][1] * grid[0][2] = 2 * 1 = 2
p[0][1] = grid[0][0] * grid[0][2] = 12345 * 1 = 12345. 12345 % 12345 = 0 ,所以 p[0][1] = 0
p[0][2] = grid[0][0] * grid[0][1] = 12345 * 2 = 24690. 24690 % 12345 = 0 ,所以 p[0][2] = 0
所以答案是 [[2],[0],[0]] 。

提示:

1 <= n == grid.length <= 105
1 <= m == grid[i].length <= 105
2 <= n * m <= 105
1 <= grid[i][j] <= 109


源码:

class Solution {
    public int[][] constructProductMatrix(int[][] grid) {
        long[] help=new long[grid.length*grid[0].length];
        long[] left=new long[grid.length*grid[0].length];
        long[] right=new long[grid.length*grid[0].length];
        left[0]=1;
        right[right.length-1]=1;
        for(int i=0;i<=grid.length-1;i++){
            for(int j=0;j<=grid[0].length-1;j++){
                help[j+i*grid[0].length]=grid[i][j];
            }
        }
        for(int i=1;i<=left.length-1;i++){
            left[i]=left[i-1]*help[i-1]%12345;

        }
        for(int j=right.length-2;j>=0;j--){
            right[j]=right[j+1]*help[j+1]%12345;          
        }
        for(int i=0;i<=help.length-1;i++){
            help[i]=left[i]*right[i]%12345;
        }
        for(int i=0;i<=grid.length-1;i++){
            for(int j=0;j<=grid[0].length-1;j++){
                grid[i][j]=(int)(help[j+i*grid[0].length]%12345);
            }
        }
        return grid;
    }
}

就一个点,把二维数组拉成一维数组,其余的和上面的题一模一样

这一步就是把二维数组拉成一维数组

 for(int i=0;i<=grid.length-1;i++){
            for(int j=0;j<=grid[0].length-1;j++){
                help[j+i*grid[0].length]=grid[i][j];
            }
        }

注意事项就是本题数有点大,要提前取余运算,以及设置long变量

long[] help=new long[grid.length*grid[0].length];
        long[] left=new long[grid.length*grid[0].length];
        long[] right=new long[grid.length*grid[0].length];
left[i]=left[i-1]*help[i-1]%12345;
right[j]=right[j+1]*help[j+1]%12345;
grid[i][j]=(int)(help[j+i*grid[0].length]%12345);
  • 9
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值