LeetCode238-除自身以外数组的乘积

最近在帮别人弄聊天机器人

虽然只是很小型的学习应用

但觉得很有意思

尤其是涉及到了知识图谱的应用

可以好好来看看


题目描述:

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

示例:

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

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

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

思路解析:

这一题可谓是有些刁钻了,因为有两个限制条件:1)不要使用除法;2)在O(n) 时间复杂度内完成此题。我们一个一个来剖析,首先,不要使用除法,这就断了我们大多数人最原本的想法。最简单的无非就是首先求得给定的nums数组中所有元素的乘积,然后依次遍历该数组,将乘积值除以当前元素值,即可得 nums 中除 nums[i] 之外其余各元素的乘积。现在题目给了条件一,也就限制了这种解法。我们再来看看条件二,要求我们算法的时间复杂度为O(n) ,这无非就是要求我们只能用一层遍历,不能超过了两层。这个条件限制了我们使用暴力法的可能,即遍历某一个元素时,继续遍历nums数组中除该元素的所有元素,相乘即可得我们想要的结果。那么只能用一层遍历,怎么搞呢?

别急,我们还是得抓住解题的一般做法,即output[i] 是怎么计算出来的,过程如下所示:

那么关键点就转换成了如何找到每个元素的左右集合,而且还得考虑时间复杂度。既然是两个左右集合,那么最容易想到的无非就是先定义两个list集合出来分别代表左右集合。然后就是各自遍历数组,分别求值。这里面都有个时间差,也就是当前output[i]只是之前所有元素的乘积,不包括当前nums[i]的值,get到了这点那么求解左右集合就很easy了。最后我们只需要再从左至右遍历一次数组,将left[i]和right[i]的值相乘即可得output[i],也就得到了我们最终想要的结果。代码如下:

class Solution(object):
    def productExceptSelf(self, nums):
        """
        空间复杂度O(n)
        :type nums: List[int]
        :rtype: List[int]
        """
        left_list, right_list = [1] * (len(nums)+1), [1] * (len(nums)+1)
        left, right = 1, 1
        result = []
        for i in range(len(nums)):
            left_list[i+1] = left_list[i] * left
            left = nums[i]
        for j in range(len(nums)-1, -1, -1):
            right = nums[j]
            right_list[j] = right_list[j+1] * right
        for index in range(1, len(nums)+1):
            result.append(left_list[index] * right_list[index])
        return result


if __name__ == "__main__":
    nums = [1, 2, 3, 4]
    result = Solution().productExceptSelf(nums)
    print(result)

执行效率还算是不错,在80%左右。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学习的学习者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值