nums라는 정수 배열이 주어진다.answer[i]는 nums[i]를 제외한 모든 요소의 곱이 되어야 한다.// 이렇게 풀면 0이 있는 경우 제대로 동작하지 않는다.
function productExceptSelf(nums) {
const n = nums.length;
const res = nums.reduce((a, b) => a * b, 1);
return nums.map(num => res / num);
}
문제점:
nums[i]의 왼쪽에 있는 모든 수의 곱nums[i]의 오른쪽에 있는 모든 수의 곱answer[i] = L[i] * R[i]왼쪽 누적 곱 계산
왼쪽 곱 저장오른쪽 누적 곱 계산
오른쪽 곱을 곱해줌최종적으로 answer[i]에는 nums[i]를 제외한 모든 값의 곱이 저장됨
function productExceptSelf(nums) {
const n = nums.length;
const left = Array(n).fill(1);
const right = Array(n).fill(1);
// 왼쪽 누적곱
for (let i = 1; i < n; i++) {
left[i] = left[i - 1] * nums[i - 1];
}
// 오른쪽 누적곱
for (let i = n - 2; i >= 0; i--) {
right[i] = right[i + 1] * nums[i + 1];
}
// 최종 곱
const answer = [];
for (let i = 0; i < n; i++) {
answer[i] = left[i] * right[i];
}
return answer;
}
실제로는 배열 두 개를 따로 쓸 필요 없이, 정답 배열 하나만 써서 왼쪽, 오른쪽을 차례로 누적할 수 있다.
function productExceptSelf(nums) {
const n = nums.length;
const answer = Array(n).fill(1);
// 1. 왼쪽 곱 누적
let left = 1;
for (let i = 0; i < n; i++) {
answer[i] = left;
left *= nums[i];
}
// 2. 오른쪽 곱 누적 및 곱셈
let right = 1;
for (let i = n - 1; i >= 0; i--) {
answer[i] *= right;
right *= nums[i];
}
return answer;
}
사실 이 방식이 직관적이지 않게 느껴질 수 있지만,
원리를 이해하려면 각 위치의 왼쪽/오른쪽 곱을 하나씩 누적해서
“자기 자신만 제외한 모든 곱”이란 게 어떻게 만들어지는지 예시를 통해 생각해보면 이해가 쉬움.
또한 예시 요소를 그대로 사용하기 보단, index를 요소에 대입해보면서 시각화를 하는 것이 점화식을 얻기 쉽다.