오늘의 문제 선정 이유
대규모 서비스와 추천 시스템처럼 여러 값의 전체 효과를 빠르게 계산해야 하는 상황과 닮아 있어, 실무형 코딩 테스트에서 자주 변형되는 유형이기 때문입니다.
문제 설명
당신은 여러 서버의 일일 처리량을 분석하는 도구를 만들고 있습니다.
정수 배열 loads가 주어질 때, 각 위치 i에 대해 loads[i]를 제외한 나머지 모든 원소의 곱을 구한 배열을 반환하세요.
단, 나눗셈은 사용할 수 없습니다.
예를 들어 loads = [3, 2, 4, 5]라면,
- 0번 위치 결과는
2 * 4 * 5 = 40
- 1번 위치 결과는
3 * 4 * 5 = 60
이런 식으로 각 위치별 결과를 계산하면 됩니다.
함수 시그니처 예시:
- Python:
def solve(loads: list[int]) -> list[int]:
- JavaScript:
function solve(loads) {}
입출력 예시
[text]입력: loads = [3, 2, 4, 5]
출력: [40, 60, 30, 24]
설명:
0번은 2*4*5 = 40
1번은 3*4*5 = 60
2번은 3*2*5 = 30
3번은 3*2*4 = 24
[text]입력: loads = [1, 0, 6, 2]
출력: [0, 12, 0, 0]
설명:
0번은 0*6*2 = 0
1번은 1*6*2 = 12
2번은 1*0*2 = 0
3번은 1*0*6 = 0
[text]입력: loads = [-1, 2, -3, 4]
출력: [-24, 12, -8, 6]
설명:
부호까지 포함해서 곱해야 한다.
0번은 2*(-3)*4 = -24
1번은 (-1)*(-3)*4 = 12
2번은 (-1)*2*4 = -8
3번은 (-1)*2*(-3) = 6
제약 조건
2 <= len(loads) <= 100000
-30 <= loads[i] <= 30
- 결과는 64비트 정수 범위 안에 들어온다고 가정
- 시간 제한: O(n) 내 풀이 권장
- 나눗셈 사용 금지
풀이 접근법
핵심 아이디어
이 문제는 각 위치에서 "왼쪽 구간의 곱"과 "오른쪽 구간의 곱"만 알면 바로 답을 만들 수 있습니다.
나눗셈을 쓰면 0이 있을 때 처리가 복잡해지고, 문제 조건에도 맞지 않습니다. 그래서 prefix product와 suffix product를 이용해 각 칸의 답을 O(n)에 구하는 방법이 가장 안정적입니다.
단계별 풀이 과정
1. 결과 배열을 1로 초기화합니다.
2. 왼쪽에서 오른쪽으로 순회하면서, 현재 위치보다 왼쪽 원소들의 곱을 결과 배열에 저장합니다.
3. 오른쪽에서 왼쪽으로 순회하면서, 현재 위치보다 오른쪽 원소들의 곱을 곱해 최종 답을 완성합니다.
코드 풀이
Python
[python]def solve(loads: list[int]) -> list[int]:
n = len(loads)
answer = [1] * n
# answer[i]에 i의 왼쪽 원소들의 곱 저장
prefix = 1
for i in range(n):
answer[i] = prefix
prefix *= loads[i]
# 오른쪽 원소들의 곱을 뒤에서부터 곱해 최종 완성
suffix = 1
for i in range(n - 1, -1, -1):
answer[i] *= suffix
suffix *= loads[i]
return answer
# 예시 실행
if __name__ == "__main__":
print(solve([3, 2, 4, 5])) # [40, 60, 30, 24]
print(solve([1, 0, 6, 2])) # [0, 12, 0, 0]
print(solve([-1, 2, -3, 4])) # [-24, 12, -8, 6]
JavaScript
[javascript]function solve(loads) {
const n = loads.length;
const answer = new Array(n).fill(1);
// answer[i]에 i의 왼쪽 원소들의 곱 저장
let prefix = 1;
for (let i = 0; i < n; i++) {
answer[i] = prefix;
prefix *= loads[i];
}
// 오른쪽 원소들의 곱을 뒤에서부터 곱해 최종 완성
let suffix = 1;
for (let i = n - 1; i >= 0; i--) {
answer[i] *= suffix;
suffix *= loads[i];
}
return answer;
}
// 예시 실행
console.log(solve([3, 2, 4, 5])); // [40, 60, 30, 24]
console.log(solve([1, 0, 6, 2])); // [0, 12, 0, 0]
console.log(solve([-1, 2, -3, 4])); // [-24, 12, -8, 6]
시간·공간 복잡도
- 시간 복잡도: O(n) — 배열을 앞에서 한 번, 뒤에서 한 번 순회합니다.
- 공간 복잡도: O(1) 추가 공간 — 정답 배열을 제외하면
prefix,suffix변수만 사용합니다.
틀리기 쉬운 포인트
- 전체 곱을 구한 뒤 각 원소로 나누는 방식은 문제 조건에 어긋납니다.
0이 포함된 경우 나눗셈 방식은 쉽게 깨집니다. prefix/suffix 방식은 그대로 동작합니다.
- 첫 번째 순회에서
answer[i] = prefix를 먼저 넣고, 그다음prefix *= loads[i]를 해야 합니다. 순서가 바뀌면 자기 자신이 포함됩니다.
유사 문제 패턴
- 구간 누적값을 이용해 특정 위치를 제외한 합이나 곱을 구하는 문제
- prefix/suffix 배열로 빗물 계산, 좌우 최대값 비교를 하는 문제
- 자기 자신을 제외한 나머지 원소들의 조건을 빠르게 계산하는 배열 전처리 문제
'Develop > 코딩 테스트' 카테고리의 다른 글
| [코딩 테스트] 2026-03-28 — 행렬 90도 회전 (0) | 2026.03.28 |
|---|---|
| [코딩 테스트] 2026-03-27 — 0/1 배낭 문제 (0) | 2026.03.27 |
| [코딩 테스트] 2026-03-25 — 슬라이딩 윈도우 최댓값 (0) | 2026.03.25 |
| [코딩 테스트] 2026-03-24 — 레벨 순서 순회 (0) | 2026.03.24 |
| [코딩 테스트] 2026-03-23 — 동적 계획법(DP) (0) | 2026.03.23 |