package com.freetymekiyan.algorithms.level.medium;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
/**
* Given an array of n integers where n > 1, nums, return an array output such that output[i] is equal to the product of
* all the elements of nums except nums[i].
* <p>
* Solve it without division and in O(n).
* <p>
* For example, given [1,2,3,4], return [24,12,8,6].
* <p>
* Follow up:
* Could you solve it with constant space complexity? (Note: The output array does not count as extra space for the
* purpose of space complexity analysis.)
* <p>
* Company Tags: Amazon, LinkedIn, Apple, Facebook, Microsoft
* Tags: Array
* Similar Problems: (H) Trapping Rain Water, (M) Maximum Product Subarray, (H) Paint House II
*/
public class ProductofArrayExceptSelf {
private ProductofArrayExceptSelf p;
/**
* Array. One-pass. O(1) Space.
* The product is actually composed of two parts, the integers on the left, and integers on the right.
* For a naive O(n) Time, O(n) Space solution.
* You can use two arrays to store products from the beginning and from the end.
* Then multiply each position in the two arrays to generate result.
* If we want to reduce space usage to O(1), we can just replace the two arrays with two integers.
*/
public int[] productExceptSelf(int[] nums) {
int n = nums.length;
int[] res = new int[n];
Arrays.fill(res, 1);
int left = 1; // Product of integers before i.
int right = 1; // Product of integers after n-1-i.
for (int i = 0; i < nums.length; i++) {
res[i] *= left; // Update result in the front.
left *= nums[i]; // Update left.
res[n - 1 - i] *= right; // Update result at the end.
right *= nums[n - 1 - i]; // Update right.
}
return res;
}
/**
* Array. Two-pass. O(1) Space.
* Scan from the beginning to store the result of products of integers on the left.
* Scan from the end to start to generate final result.
*/
public int[] productExceptSelfB(int[] nums) {
int n = nums.length;
int[] res = new int[n];
res[0] = 1;
for (int i = 1; i < n; i++) {
res[i] = res[i - 1] * nums[i - 1];
}
int right = 1;
for (int i = n - 1; i >= 0; i--) {
res[i] *= right;
right *= nums[i];
}
return res;
}
@Before
public void setUp() {
p = new ProductofArrayExceptSelf();
}
@Test
public void testExamples() {
int[] nums = {1, 2, 3, 4};
int[] res = {24, 12, 8, 6};
Assert.assertArrayEquals(res, p.productExceptSelf(nums));
Assert.assertArrayEquals(res, p.productExceptSelfB(nums));
nums = new int[]{1, 2, 3};
res = new int[]{6, 3, 2};
Assert.assertArrayEquals(res, p.productExceptSelf(nums));
Assert.assertArrayEquals(res, p.productExceptSelfB(nums));
nums = new int[]{1, 2};
res = new int[]{2, 1};
Assert.assertArrayEquals(res, p.productExceptSelf(nums));
Assert.assertArrayEquals(res, p.productExceptSelfB(nums));
}
@After
public void tearDown() {
p = null;
}
}