首页 > 其他分享 >238题:除自身以外数组的乘积

238题:除自身以外数组的乘积

时间:2023-12-13 23:34:13浏览次数:38  
标签:乘积 nums int res zeroCount 238 数组

238题:除自身以外数组的乘积

写作背景:由于最近在练习leetcode,这道题刚开始思路不太清晰,所以将自己的解题思路记录下来,以便后续复习。

题目描述:

  • 给你一个整数数组 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 位 整数范围内
    
  • 进阶:你可以在 O(1) 的额外空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组 不被视为 额外空间。)

解题思路:

  • 1.暴力解法:遍历数组,每次遍历时,将当前元素置为1,然后遍历数组,将其他元素相乘,得到结果,将结果放入结果数组中,时间复杂度为O(n^2)
  • 2.优化解法:遍历一遍数组,得到数组的乘积,然后遍历数组,将数组的乘积除以当前元素,得到结果,将结果放入结果数组中,时间复杂度为O(n)
  • 难点:不能使用除法,且时间复杂度为O(n)
  • 解决思路:使用乘积倒数来计算结果。
public class P238 {

    public int[] productExceptSelf(int[] nums) {
        if (nums.length == 0){
            return nums;
        }
        int sumMultiply = 1;
        int[] res = new int[nums.length];
        int zeroCount = 0;
        int zeroPos = -1;

        for (int i = 0;i< nums.length;i++) {
            if (0 != nums[i])
                sumMultiply *= nums[i];
            else {
                zeroCount++;
                zeroPos = i;
            }
        }

        if (zeroCount > 1)
            return res;
        else if (zeroCount == 1) {
            res[zeroPos] = sumMultiply;
            return res;
        }else {
            for (int i = 0;i<nums.length;i++) {
                res[i] = (int) (sumMultiply * calculateReciprocal(nums[i]));
            }
        }
        return res;
    }

    // 计算一个数的倒数
    private static double calculateReciprocal(int val) {
        if (val == 0) {
            return 0;
        }

        boolean negative = false;
        // 判断是否是负数
        if (val < 0) {
            negative = true;
            val = -val;
        }
        int iniVal = 1;
        double iniInt = 1.0;
        double iniDouble = 0.1;
        double finalVal = 0.0;
        int maxAcc = 16;
        int iniAcc = 0;

        do {
            int count = 0;
            // 将 iniInt 和 iniVal 调整到适当的范围
            while (iniVal < val) {
                iniVal *= 10;
                iniInt *= iniDouble;
            }

            // 计算倒数的整数部分
            while (iniVal >= val) {
                iniVal -= val;
                count++;
            }

            // 累加整数部分
            finalVal += iniInt * count;
            iniAcc++;
        } while (iniVal != 0 && iniAcc < maxAcc);

        return negative ? -finalVal : finalVal;
    }
}
  • 3.还可以通过数学方法计算一个数倒数并且不涉及除法,解决方法:使用对数来计算倒数,即:1/x = e^(-ln(x)),这样就可以使用乘积倒数来计算结果。
    但是此方法由于java中的double类型精度问题,导致结果不准确,所以不推荐使用,但是可以作为一种思路。
public class P238 {

    public int[] productExceptSelf(int[] nums) {
        if (nums.length == 0){
            return nums;
        }
        int sumMultiply = 1;
        int[] res = new int[nums.length];
        int zeroCount = 0;
        int zeroPos = -1;

        for (int i = 0;i< nums.length;i++) {
            if (0 != nums[i])
                sumMultiply *= nums[i];
            else {
                zeroCount++;
                zeroPos = i;
            }
        }

        if (zeroCount > 1)
            return res;
        else if (zeroCount == 1) {
            res[zeroPos] = sumMultiply;
            return res;
        }else {
            for (int i = 0;i<nums.length;i++) {
                res[i] = (int) (sumMultiply * calculateReciprocal(nums[i]));
            }
        }
        return res;
    }

    // 计算一个数的倒数
    private static double calculateReciprocal(int val) {
        if (val == 0) {
            return 0;
        }
        boolean negative = false;
        // 判断是否是负数
        if (val < 0) {
            negative = true;
            val = -val;
        }
        return negative ? -Math.exp(-Math.log(val)) : Math.exp(-Math.log(val));
    }
}

标签:乘积,nums,int,res,zeroCount,238,数组
From: https://www.cnblogs.com/bearcanlight/p/17900190.html

相关文章

  • 代码随想录算法训练营第一天 | 数组理论基础,704. 二分查找,27. 移除元素
    一、数组理论基础学习前:1.数组定义一些在内存上连续存储的相同数据类型的数据的集合2.数组特征便于查询数组元素,不便于增删数据元素学习后:对于Java,二维数组不一定在内存上连续。如int[i][j],唯一确定的是int[i][]在内存上连续二、704.二分查找LeetCode704.二分查找......
  • delphi 变体Variant数组常用操作
    变体Variant数组常用操作代码procedureTForm1.Button1Click(Sender:TObject);varArr1,Arr2,Arr3:Variant;I,J:Integer;begin//创建包含10个整数类型元素的变体数组Arr1:=VarArrayCreate([0,9],varInteger);//创建2维数组,其中第1维是3个元素,第2维是5......
  • 将value值是true、false的转为1、0,然后将yData数组里的值全部加个2
         ......
  • 将第2层数据中的数组对象中的ts属性、value属性遍历单独存放到一个新数组中xData、yDa
          ......
  • js中数组map和集合map
    js中数组的map:使用情况:想要对一个数组进行操作,然后又不想改变原来的数组数据,还想基于原来数组的数据进行改造,那么可以使用map写法一:letarr=[1,2,3,4]letnewArr=arr.map(item=>{return++item})console.log(newArr,arr)//输出[2,3,4,5][1,2,3,4]letarr=[1......
  • 二维数组页码分页
    $param=$this->request->param();$data=[['id'=>1,'name'=>'11'],['id'=>2,'name'=>'22'],['id'=>3,&......
  • 【教3妹学编程-算法题】交换得到字典序最小的数组
    3妹:2哥2哥,你有没有看到新闻:周海媚姐因病医治无效,于2023年12月11日离开了我们。2哥 :看到了,真是个悲伤的消息,早晨还看到辟谣,以为没事了呢。3妹:是啊,#再见周芷若#2哥:童年的女神,周海媚演的这版“周芷若”真的很深入人心!被评为“最美周芷若”3妹:哎,人有生老病死,R.I.P.2哥:唉,说点高兴的......
  • get请求数组参数,格式转换
    get请求转码关于qs插件qs是一个增加了一些安全性的查询字符串解析和序列化字符串的库。可以进行对象与字符串之间的一个转换。安装qsaxios中自带qs无需下载,若单独下载只需npminstallqs即可使用组件中单独引入importqsfrom'qs'或者全局引入(main.js)Vue.prototyp......
  • Java-04数组
    tip:[start]程序=逻辑+数据,数组是存储数据的强而有力的手段。——闫学灿tip:[end]一维数组数组的定义数组的定义方式和变量类似。java中数组的定义[]是写在数组名前面(与c++区分),开辟长度需要new,即面向对象。publicclassMain{publicstaticvoidmain(String[]......
  • 树状数组
    树状数组所维护的数组记为\(a\),\(n\)表示\(a\)中元素个数,\(lowbit(i)\)表示最低位\(1\)和后面所有\(0\)组成的数,\(c[i]\)表示\(a\)区间\([i-lowbit(i)+1,i]\)的和。\(add(k,x)\):单点修改,表示\(a[k]=a[k]+x\),时间复杂度:\(O(logn)\)。\(sum\):区间查询,\(sum(k)\)表示\(a\)区......