notes/OJ notes/pages/Leetcode Product-of-Array-Except-Self.md
2022-09-06 20:22:48 +08:00

3.5 KiB

Leetcode Product-of-Array-Except-Self

2022-09-05 14:27

Algorithms:

#algorithm #prefix_sum

Data structures:

#DS

Difficulty:

#coding_problem #difficulty_medium

Additional tags:

#leetcode #CS_list_need_understanding

Revisions:

N/A


Problem

Given an integer array nums, return an array answer such that answer[i] is equal to the product of all the elements of nums except nums[i].

The product of any prefix or suffix of nums is guaranteed to fit in a 32-bit integer.

You must write an algorithm that runs in O(n) time and without using the division operation.

Examples

Example 1:

Input: nums = [1,2,3,4] Output: [24,12,8,6]

Example 2:

Input: nums = [-1,1,0,-3,3] Output: [0,0,9,0,0]

Constraints

  • 2 <= nums.length <= 105
  • -30 <= nums[i] <= 30
  • The product of any prefix or suffix of nums is guaranteed to fit in a 32-bit integer.

Thoughts

[!summary] This is a variation of #prefix_sum

I thought of using prefix product, a variation of prefix_sum, which perfectly fits the requirement.

First iteration:

keep two arrays: the suffix product and the prefix product of the nums array.

Then, ans = prefix[i] * suffix[i]

Second iteration:

It's like rolling snowball, the suffix sum variable gets reused

We can use only one output array:

write the prefix to the ans array, and update it from end using suffix sum variable.

This achieves the O(1) space except output requirement.

Third iteration:

Since the multiplying process is independent, and can be reversed, We can do that in one loop.

1 * A * B == 1 * B * A

If we initialize the ans array as one, we can do that in one loop.

Solution

Third version:

class Solution {
public:
  vector<int> productExceptSelf(vector<int> &nums) {
    // Optimized one-pass prefix sum & suffix sum
    int size = nums.size();

    vector<int> ans(size, 1);

    int prefix = 1, suffix = 1;

    for (int i = 0; i < size; i++) {
      ans[i] *= prefix;
      prefix *= nums[i];

      ans[size - i - 1] *= suffix;
      suffix *= nums[size - i - 1];
    }

    return ans;
  }
};

Second version:

class Solution {
public:
  vector<int> productExceptSelf(vector<int> &nums) {
    // Optimized prefix sum & suffix sum
    int size = nums.size();
    vector<int> ans(size);

    ans[0] = 1;
    for (int i = 1; i < size; i++) {
      ans[i] = ans[i - 1] * nums[i - 1];
    }

    int suffix = 1;

    for (int i = size - 1; i >= 0; i--) {
      ans[i] = ans[i] * suffix;
      suffix = suffix * nums[i];
    }

    return ans;
  }
};

First iteration:

class Solution {
public:
  vector<int> productExceptSelf(vector<int> &nums) {
    // method 1: prefix sum & suffix sum
    vector<int> ans;
    vector<int> suffix;
    int size = nums.size();
    ans.resize(size);
    suffix.resize(size);

    ans[0] = 1;
    for (int i = 1; i < size; i++) {
      ans[i] = ans[i - 1] * nums[i - 1];
    }

    suffix[size - 1] = 1;
    for (int i = size - 2; i >= 0; i--) {
      suffix[i] = suffix[i + 1] * nums[i + 1];
    }

    for (int i = 0; i < size; i++) {
      ans[i] = ans[i] * suffix[i];
    }

    return ans;
  }
};