leetcode面试经典150题——13除自身以外数组的乘积

文章讲述了如何在给定整数数组中,不使用除法,在O(n)时间内计算每个元素除自身之外的乘积,提供了两种方法:一种是利用两个向量分别存储左右两侧元素乘积,另一种是将答案数组本身作为左侧乘积,动态维护右侧乘积。
摘要由CSDN通过智能技术生成

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

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

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

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

示例 1:

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

显然如果可以使用除法,那么我们计算所有元素的乘积sum,那么answer[i] = sum/nums[i]。那么我们考虑暴力法,直接求除了这个元素外的所有元素乘积,那么对于求每一个answer[i],我们都需要遍历一遍数组nums,那么 遍历n次,因此我们需要的时间复杂度为o(n²),超过了题目要求的o(n),时间复杂度,所以我们现在需要考虑的是只需要遍历常量遍数组nums,就可以得出answer的算法。

方法一:
我们知道answer[i]表示除了nums[i]以外所有元素的乘积,那么我们如果把他们按照相对nums[i]的位置,我们可以分为左边的部分left,和右边的部分right,那么answer[i]就能表示nums[i]左边部分的乘积乘以右边部分的乘积。顺着这个思路我们定义两个大小为n的vector:left,right.那么就有left[i]表示nums[i]左边所有元素的乘积,其中left[0] = 1(左边没有元素),right[i]表示nums[i]右边所有元素的乘积,同样的right[n-1] = 1(右边没有元素)。而left[i] = left[i-1]*nums[i-1],i-1左边所有的元素乘以i-1就是i左边所有的元素,同理rigjt[i] = right[i+1]*nums[i+1].最后answer[i] = left[i]*right[i].
时间复杂度o(n)
空间复杂度o(n)

vector<int> productExceptSelf(vector<int>& nums) {
	int n = nums.size();
	vector<int> left(n);
	vector<int> right(n);
	left[0] = 1;
	right[n-1] = 1;
	for(int i=1;i<n;i++){//初始化left数组,从初值left[0]开始往后
		left[i] = left[i-1]*nums[i-1];
	}
	for(int i=n-2;i>=0;i--){//初始化right,从 初值right[n-1]往前
		right[i] = right[i+1]*nums[i+1];
	}
	for(int i=0;i<n;i++){//求answer数组,这里直接用nums数组
		nums[i] = left[i]*right[i];
	}
	return nums;
}

方法二:假设我们answer数组不算做本算法的存储空间,我们方法一的空间复杂度为o(n),我们需要不定义left数组和right数组,使得我们空间复杂度变为o(1),所以此方法是对方法一的改进,我们把answer作为我们的left数组,定义一个变量right,动态的更新right,使得其表示为右侧所有元素的乘积。
时间复杂度o(n)
空间复杂度o(1)

vector<int> productExceptSelf(vector<int>& nums) {
	int n = nums.size();
	vector<int> answer(n);//answer作为left数组 
	answer[0] = 1;//第一个元素左边没有元素,即为1
	for(int i=1;i<n;i++){//初始化answer数组,即初始化left
		answer[i] = answer[i-1]*nums[i-1];
	}
	int right = 1;
	for(int i = n-1;i>=0;i--){
		answer[i] = answer[i]*right;//左边元素乘积*右边元素乘积 
		right = right*nums[i];//动态更新right表示为右侧所有元素的乘积
	}
	return answer;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值