LeetCode 面试经典 150_数组/字符串_除自身以外数组的乘积(13_238_C++_中等)
题目描述:
给你一个整数数组 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
输入 保证 数组 answer[i] 在 32 位 整数范围内
题解:
解题思路:
思路一(暴力破解法):
1、题目要求除自身以外数组的乘积。可以对每个位置除自身以外的乘积都算一遍。
例:nums = [1,2,3,4]
① 计算除 1 以外的乘积 ans=[24]
② 计算除 2 以外的乘积 ans=[24,12]
③ 计算除 3 以外的乘积 ans=[24,12,8]
④ 计算除 4 以外的乘积 ans=[24,12,8,6]
如果某一位置元素为 0 ,可计算当前位置以外元素的乘积。其余位置为0。
例:nums = [-1,1,0,-3,3],ans=[0,0,9,0,0]
2、复杂度分析:
① 时间复杂度:O(N²),N代表数组的长度,使用了双重循环所以为O(N²)。
② 空间复杂度:O(1),我们只需常数空间存放若干变量。
思路二(前缀积):
1、例 :nums = [1,2,3,4]
① 计算除 1 以外的乘积,是(1) × (2×3×4) 。注 :(1) 是前缀积 ,(2×3×4) 是后缀积
② 计算除 2 以外的乘积,是(1) × (3×4)
③ 计算除 3 以外的乘积,是(1×2) × (4)
④ 计算除 4 以外的乘积,是(1×2×3) × (1)
发现除自身以外元素的乘积 = 前缀积 × 后缀积
2、复杂度分析
① 时间复杂度:O(N),其中 N 是数组中的元素数量。因遍历2遍数组。
② 空间复杂度:O(N),其中 N 是数组中的元素数量。创建两个额外的容器存放前缀之积和后缀之积。
代码实现
代码实现(思路一(暴力破解)):
cpp
class Solution1 {
public:
// 函数定义:返回一个数组,数组中的每个元素是除了当前元素之外所有元素的乘积
vector<int> productExceptSelf(vector<int>& nums) {
// 创建一个与 nums 同大小的结果数组 ans 用于存储每个位置的结果
vector<int> ans(nums.size());
// 外层循环遍历 nums 数组的每个元素
for(int i = 0; i < nums.size(); i++) {
// 初始化乘积变量 mul 为 1,用于计算当前位置 i 除去 nums[i] 之外所有元素的乘积
int mul = 1;
// 内层循环遍历数组 nums 中的每个元素
for(int j = 0; j < nums.size(); j++) {
// 如果当前索引 j 等于 i,则跳过,避免计算当前元素的乘积
if(j == i) {
continue;
}
// 累乘 nums 中所有不等于当前位置 i 的元素
mul = mul * nums[j];
// 如果乘积为 0,则进入特殊处理流程
if(mul == 0) {
// 如果乘积为 0,重新计算除去当前为 0 元素外其他元素的乘积
int mul2 = 1;
// 再次遍历 nums 数组,计算排除 j 元素外所有其他元素的乘积
for(int n = 0; n < nums.size(); n++) {
// 跳过索引为 j 的元素
if(n == j) {
continue;
}
// 累乘 nums 中除去 j 索引的其他元素
mul2 = mul2 * nums[n];
}
// 将排除 0 后的乘积存储到 ans[j]
ans[j] = mul2;
// 返回最终结果数组 ans
return ans;
}
}
// 将当前位置 i 的乘积(排除当前元素的乘积)存储到 ans[i]
ans[i] = mul;
}
// 返回最终的结果数组 ans
return ans;
}
};
代码实现(思路二(双指针)):
cpp
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
vector<int> ans(nums.size(), 0);
ans[0] = 1;
// 存储前缀之积
for (int i = 1; i < nums.size(); ++i) {
ans[i] = ans[i - 1] * nums[i - 1];
}
// end_mul存储当前遍历位置的后缀之积
int end_mul = 1;
// 我们在求出后缀之积的同时可以计算除自身以外数组的乘积,来存储到ans中
for (int i = nums.size() - 2; i >= 0; --i) {
end_mul = end_mul * nums[i + 1];
ans[i] = ans[i] * end_mul;
}
return ans;
}
};
以思路二为例进行调试
cpp
#include<iostream>
#include<vector>
using namespace std;
vector<int> productExceptSelf3(vector<int>& nums){
vector<int> ans(nums.size(),0);
ans[0]=1;
//存储前缀之积
for(int i=1;i<nums.size();++i){
ans[i]=ans[i-1]*nums[i-1];
}
//end_mul存储当前遍历位置的后缀之积
int end_mul=1;
//我们在求出后缀之积的同时可以计算除自身以外数组的乘积,来存储到ans中
for(int i=nums.size()-2;i>=0;--i){
end_mul=end_mul*nums[i+1];
ans[i]=ans[i]*end_mul;
}
return ans;
}
int main(){
vector<int> nums={2,4,1,3,5};
vector<int> ans=productExceptSelf3(nums);
for(const auto &t:ans){
cout<<t<<" ";
}
return 0;
}
LeetCode 面试经典 150_数组/字符串_除自身以外数组的乘积(13_238)原题链接
欢迎大家和我沟通交流(✿◠‿◠)