LC 238. 除自身以外数组的乘积
题目描述
这是 LeetCode 上的 238. 除自身以外数组的乘积 ,难度为 中等。
给你一个整数数组 nums
,返回 数组 answer
,其中 $answer[i]$ 等于 nums
中除 $nums[i]$ 之外其余各元素的乘积 。
题目数据 保证 数组 nums
之中任意元素的全部前缀元素和后缀的乘积都在 $32$ 位 整数范围内。
请不要使用除法,且在 $O(n)$ 时间复杂度内完成此题。
示例 1:1
2
3输入: nums = [1,2,3,4]
输出: [24,12,8,6]
示例 2:1
2
3输入: nums = [-1,1,0,-3,3]
输出: [0,0,9,0,0]
提示:
- $2 <= nums.length <= 10^5$
- $-30 <= nums[i] <= 30$
- 保证 数组
nums
之中任意元素的全部前缀元素和后缀的乘积都在 $32$ 位 整数范围内
进阶:你可以在 $O(1)$ 的额外空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。)
前缀和
根据题意,对于每个 $ans[i]$ 均由两部分组成:
因此我们可以运用「前缀和」思想,使用数组 s1
和 s2
分别计算范围 $[1, x]$ 的前缀乘 和 范围 $[x, n]$ 的后缀乘法(前缀和数组下标默认从 $1$ 开始),即 $s1[i]$ 代表范围 $[1,i]$ 的前缀乘值,$s2[i]$ 代表范围 $[i, n]$ 的后缀乘值。
预处理完 s1
和 s2
之后,即可计算每个 $ans[i - 1] = s1[i - 1] \times s2[i + 1]$(ans
数组下标从 $0$ 开始)。
Java 代码:1
2
3
4
5
6
7
8
9
10
11
12class Solution {
public int[] productExceptSelf(int[] nums) {
int n = nums.length;
int[] s1 = new int[n + 10], s2 = new int[n + 10];
s1[0] = s2[n + 1] = 1;
for (int i = 1; i <= n; i++) s1[i] = s1[i - 1] * nums[i - 1];
for (int i = n; i >= 1; i--) s2[i] = s2[i + 1] * nums[i - 1];
int[] ans = new int[n];
for (int i = 1; i <= n; i++) ans[i - 1] = s1[i - 1] * s2[i + 1];
return ans;
}
}
C++ 代码:1
2
3
4
5
6
7
8
9
10
11
12class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int n = nums.size();
vector<int> s1(n + 2, 1), s2(n + 2, 1);
for (int i = 1; i <= n; i++) s1[i] = s1[i - 1] * nums[i - 1];
for (int i = n; i >= 1; i--) s2[i] = s2[i + 1] * nums[i - 1];
vector<int> ans(n);
for (int i = 1; i <= n; i++) ans[i - 1] = s1[i - 1] * s2[i + 1];
return ans;
}
};
Python 代码:1
2
3
4
5
6
7
8
9
10class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
n = len(nums)
s1, s2 = [1] * (n + 2), [1] * (n + 2)
for i in range(1, n + 1):
s1[i] = s1[i - 1] * nums[i - 1]
for i in range(n, 0, -1):
s2[i] = s2[i + 1] * nums[i - 1]
ans = [s1[i - 1] * s2[i + 1] for i in range(1, n + 1)]
return ans
TypeScript 代码:1
2
3
4
5
6
7
8
9function productExceptSelf(nums: number[]): number[] {
const n = nums.length;
const s1 = new Array(n + 2).fill(1), s2 = new Array(n + 2).fill(1);
for (let i = 1; i <= n; i++) s1[i] = s1[i - 1] * nums[i - 1];
for (let i = n; i >= 1; i--) s2[i] = s2[i + 1] * nums[i - 1];
const ans = new Array(n);
for (let i = 1; i <= n; i++) ans[i - 1] = s1[i - 1] * s2[i + 1];
return ans;
};
- 时间复杂度:$O(n)$
- 空间复杂度:$O(n)$
前缀和(空间优化)
题目的进阶部分要求我们使用 $O(1)$ 空间来做(不算 ans
数组)。
这样很好处理,按照我们解法一的思路,将两部分分开算即可:建立 ans
数组,先从前往后遍历 nums
,计算每个 $ans[i]$ 前缀乘值部分,再从后往前遍历 nums
,计算每个 $ans[i]$ 后缀乘值的部分,两部分相乘即是最终的 $ans[i]$。
Java 代码:1
2
3
4
5
6
7
8
9
10
11
12
13class Solution {
public int[] productExceptSelf(int[] nums) {
int n = nums.length;
int[] ans = new int[n];
for (int i = 1, j = 1; i <= n; i++) {
ans[i - 1] = j; j *= nums[i - 1];
}
for (int i = n, j = 1; i >= 1; i--) {
ans[i - 1] *= j; j *= nums[i - 1];
}
return ans;
}
}
C++ 代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int n = nums.size();
vector<int> ans(n, 1);
for (int i = 1, j = 1; i <= n; i++) {
ans[i - 1] = j; j *= nums[i - 1];
}
for (int i = n, j = 1; i >= 1; i--) {
ans[i - 1] *= j; j *= nums[i - 1];
}
return ans;
}
};
Python 代码:1
2
3
4
5
6
7
8
9
10
11
12
13class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
n = len(nums)
ans = [1] * n
j = 1
for i in range(1, n + 1):
ans[i - 1] *= j
j *= nums[i - 1]
j = 1
for i in range(n, 0, -1):
ans[i - 1] *= j
j *= nums[i - 1]
return ans
TypeScript 代码:1
2
3
4
5
6
7
8
9
10
11function productExceptSelf(nums: number[]): number[] {
const n = nums.length;
const ans = new Array(n).fill(1);
for (let i = 1, j = 1; i <= n; i++) {
ans[i - 1] *= j; j *= nums[i - 1];
}
for (let i = n, j = 1; i >= 1; i--) {
ans[i - 1] *= j; j *= nums[i - 1];
}
return ans;
};
- 时间复杂度:$O(n)$
- 空间复杂度:$O(1)$
最后
这是我们「刷穿 LeetCode」系列文章的第 No.238
篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。
在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。
为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。
在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!