首页 > Java > Java面试题 > 正文

[LeetCode]238. 除自身以外数组的乘积解题思路

做棵大树
发布: 2020-06-06 17:22:57
原创
244 人浏览过

题目

给你一个长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。

示例:

输入: [1,2,3,4]
输出: [24,12,8,6]

提示:题目数据保证数组之中任意元素的全部前缀元素和后缀(甚至是整个数组)的乘积都在 32 位整数范围内。

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

进阶: 你可以在常数空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。)。

解法

拿到题目首先的想法是:两次for循环,一次乘积一次做除法。但是后来发现说明中注明不要使用除法,便只能向其他方法。

既然是算除了自己之外的累乘,便可以以当前所在位置为分割点,分别计算左侧元素乘积 和 右侧元素乘积,之后再进行相乘。

对此由以下解法:

算法一(摘自LeetCode官方解法):

初始化两个空数组 L 和 R。对于给定索引 i,L[i] 代表的是 i 左侧所有数字的乘积,R[i] 代表的是 i 右侧所有数字的乘积。

我们需要用两个循环来填充 L 和 R 数组的值。对于数组 L,L[0] 应该是 1,因为第一个元素的左边没有元素。对于其他元素:L[i] = L[i-1] * nums[i-1]

同理,对于数组 RR[length-1] 应为 1。length 指的是输入数组的大小。其他元素:R[i] = R[i+1] * nums[i+1]

当 R 和 L 数组填充完成,我们只需要在输入数组上迭代,且索引 i 处的值为:L[i] * R[i]

class Solution {
    public int[] productExceptSelf(int[] nums) {
  int arrLen = nums.length;
  int[] leftNums = new int[arrLen];
  int[] rightNums = new int[arrLen];
  leftNums[0] = 1;rightNums[arrLen-1] = 1;
  
  for(int i = 1; i < arrLen; i++){
   leftNums[i] = leftNums[i-1] * nums[i-1];
   rightNums[arrLen-i-1] = rightNums[arrLen-i] * nums[arrLen-i];
  }
  
  for(int i = 0; i < arrLen; i++){
   leftNums[i] *= rightNums[i];
  }
  
  return leftNums;
 }
}
登录后复制

复杂度分析

时间复杂度O(N),其中 N 指的是数组 nums 的大小。预处理 L 和 R 数组以及最后的遍历计算都是 O(N) 的时间复杂度。

空间复杂度O(N),其中 N 指的是数组 nums 的大小。使用了 L 和 R 数组去构造答案,L 和 R 数组的长度为数组 nums 的大小。

算法二:共享数组方式

整体思路和官方解题思路相同:左乘*右乘

定义返回数组 returnNums 并将其看作共享数组,同时从左右两端填充数据;之后定义 left,right 来存储左右乘积并循环迭代更新。

  1. 在两指针交会前,只需对数组进行简单的填充即可;

  2. 在两者交互时(仅发生在奇数长度)其填充值为 left*right

  3. 两者交汇后,数组的值应填入最终值:因为左侧部分已经存储了左乘积,而即将计算得到右乘积;右侧部分已存储了右乘积,即将获得左乘积。故直接相乘即可。returnNums[i] = left returnNums[j] = right

class Solution {
    public int[] productExceptSelf(int[] nums) {
        int arrLen = nums.length;
        int[] returnNums = new int[arrLen];
        int left = 1, right = 1;    // 临时存储
        returnNums[0] = 1; returnNums[arrLen-1] = 1;
        for(int i = 1, j = arrLen-2; i < arrLen; i++, j--){
            left *= nums[i-1];
            right *= nums[j+1];
            if(i < j){  // 两指针为交会
                returnNums[i] = left;
                returnNums[j] = right;
            }else if(i == j){   // 两指针重合,奇数位情况下发生
                returnNums[i] = left*right;
            }else{              // 两指针错位
                returnNums[i] *= left;
                returnNums[j] *= right;
            }
        }
        return returnNums;
    }
}
登录后复制

复杂度分析

时间复杂度O(N),同上一解题方式相同,进行了一次长度为N的循环,其时间复杂度为O(N)。

空间复杂度O(1),题目中所述,返回数组的空间不算,故所使用的额外存储空间为 left 和 right。故只有常数级别的空间复杂度。

以上是[LeetCode]238. 除自身以外数组的乘积解题思路的详细内容。更多信息请关注PHP中文网其他相关文章!

相关标签:
1
来源:php.cn
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责声明 Sitemap
PHP中文网:公益在线PHP培训,帮助PHP学习者快速成长!