LeetCode 238——Product of Array Except Self

Given an array nums of n integers where n > 1,  return an array output such that output[i] is equal to the product of all the elements of nums except nums[i].

Example:

Input:[1,2,3,4]

Output:[24,12,8,6]

Note: Please solve it without division and in O(n).

Follow up:
Could you solve it with constant space complexity? (The output array does not count as extra space for the purpose of space complexity analysis.)

 


 

说实话,这道题做的让我感觉被完爆了。如果形容的再具体一点的话,那可能就是感觉没资格和大家对线吧。

首先我没有注意到 without division 这个关键词,而自做聪明的想到了将数组中所有元素做乘积之后再在对应的位置使用除法即可。进而想到了全部元素乘积之后的结果可能超出int范围,所以应该先求出除第一个元素以外所有元素的乘积,然后再在每次都到对应output的时候将上一个元素乘回来。最后又想到了,元素中可能存在有0,那么0是不能作为除数的;但是通过总结规律发现:如果存在一个0的时候,数组除0所在位置以外,其他位置的output都是0,如果存在两个及以上的0的时候,所有的output均为0。根据这个结果想到分情况处理即可,虽然略显复杂,但是能得到正确结果总是好的。

上边在这个方法做出的结果是没有问题的,时间复杂度和最优解是一样的。但是,出发点错了,题目AC也是错的。

下边来说说正确的解法,这次算是真正领略到了 double pointer 思想的魅力:

题目要求根据数组nums求出output,并且任意合法的i对应的output[i],是nums中除nums[i]以外的其他元素的乘积。通过 double pointer 思想可以将output[i]的值分为两部分,nums[i]左边的元素的乘积结果和右边的元素的乘积结果的乘积,这样说起来有点绕口,也就是 output[i] = proLeft * proRight。

这样解题步骤就分为了两步:

  1. 从数组最右端开始,将output[n - 1]设置为 1(因为 n - 1 处右侧没有元素,所以他的右侧乘积结果为1),起始位置为 n - 2,开始循环,每次令 right *= nums[i + 1] 并 output[i] = right,循环结束后令 i -= 1,直至 i < 0。
  2. 从数组最左端开始,起始位置为0,开始循环,每次令left *= nums[i - 1] 并 output[i] *= left,循环结束后令 i += 1,直至 i > n - 1

看着整个思路略显复杂,但是写出来的代码简洁美观,思路清晰。和我的代码比起来,用惊为天人来形容一点都不为过。

最佳的解题思路和我开始的解题思路都会在下边放出。

 


 

最佳解题思路:

class Solution {
    public int[] productExceptSelf(int[] nums) {
        int numLen = nums.length;
        int[] result = new int[numLen];

        result[numLen - 1] = 1;
        for (int i = numLen - 2, right = 1; i >= 0; --i) {
            right *= nums[i + 1];
            result[i] = right;
        }

        for (int i = 1, left = 1; i < numLen; ++i) {
            left *= nums[i - 1];
            result[i] *= left;
        }

        return result;
    }
}

 

我的失败解题思路:

class Solution {
    public int[] productExceptSelf(int[] nums) {
        int numLen = nums.length;
        int mul = 1;
        int[] result = new int[numLen];
        int zeroNum = 0;
        for (int elem : nums) {
            if (elem == 0) {
                ++zeroNum;
            }
        }

        if (zeroNum == 0) {
            for (int i = 1; i < nums.length; ++i) {
                mul *= nums[i];
            }

            for (int i = 0; i < numLen; ++i) {
                if (i != 0) {
                    mul = mul / nums[i] * nums[i - 1];
                }
                result[i] = mul;
            }
        } else if (zeroNum == 1) {
            int zeroIndex = -1;
            for (int i = 0; i < numLen; ++i) {
                if (nums[i] == 0) {
                    zeroIndex = i;
                } else {
                    mul *= nums[i];
                }
            }
            Arrays.fill(result, 0);
            result[zeroIndex] = mul;
        } else {
            Arrays.fill(result, 0);
        }

        return result;
    }
}

 


如有错误,欢迎指摘。也欢迎通过左上角的“向TA提问”按钮问我问题,我将竭力解答你的疑惑。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值