1010. Pairs of Songs With Total Durations Divisible by 60
2026-04-10
Leetcode 1010번 풀이
문제
Pairs of Songs With Total Durations Divisible by 60
풀이 1
아이디어
두 곡의 재생 시간 합이 60의 배수인 쌍을 구해야 한다. 브루트 포스로 모든 쌍을 확인하면 O(N²)이지만, time의 크기가 최대 6×10⁴이므로 시간 초과가 발생한다.
그래서 1000 이하의 60의 배수(60, 120, …, 960) 집합을 미리 준비하고, 각 곡 t를 순회하면서 total - t가 이전에 등장한 적 있는지 Map에서 조회하는 방법을 썼다.
순서를 고려하지 않는 단순 쌍이기 때문에 이대로만 하면 순서가 뒤바뀐 쌍이 중복으로 세어진다. 따라서 Map을 미리 채우지 않고, 짝을 먼저 찾은 뒤 현재 t를 Map에 등록하는 순서로 처리한다. 이렇게 하면 인덱스 i < j인 방향으로만 쌍이 카운트되어 중복이 발생하지 않는다..
코드
function numPairsDivisibleBy60(time: number[]): number {
const totals = new Set([60, 120, 180, 240, 300, 360, 420, 480, 540, 600, 660, 720, 780, 840, 900, 960]);
const timeMap = new Map(); // key: time, value: count. 이 map 안에서만 찾을 것임. (중복 방지)
let answer = 0;
for (const t of time) {
for (const total of totals) {
if (total < t) continue;
answer += timeMap.get(total - t) ?? 0;
}
timeMap.set(t, (timeMap.get(t) ?? 0) + 1);
}
return answer;
}시간 / 공간 복잡도
- 시간 복잡도: O(N) — 60의 배수 집합 크기가 상수(16개)이므로 각 원소당 O(1) 처리
- 공간 복잡도: O(N) — 최악의 경우 모든 시간 값을 맵에 저장
풀이 2
아이디어
풀이 1과 동일한 구조이지만, 실제 시간 값 대신 60으로 나눈 나머지를 Map의 키로 사용한다.
(a + b) % 60 == 0이 되려면 두 나머지의 합이 0 또는 60이어야 한다. 따라서 현재 t의 나머지가 rem일 때, 짝이 되는 나머지(complement)는 다음과 같다.
rem == 0이면 →complement = 0- 그 외엔 →
complement = 60 - rem
이렇게 하면 내부 루프 없이 O(1)로 짝을 조회할 수 있고, Map의 키 범위도 0~59로 고정된다.
코드
function numPairsDivisibleBy60(time: number[]): number {
const remainderMap = new Map<number, number>(); // key: t % 60, value: count
let answer = 0;
for (const t of time) {
const rem = t % 60;
const complement = rem === 0 ? 0 : 60 - rem;
answer += remainderMap.get(complement) ?? 0;
remainderMap.set(rem, (remainderMap.get(rem) ?? 0) + 1);
}
return answer;
}시간 / 공간 복잡도
- 시간 복잡도: O(N) — 각 원소를 한 번씩 순회
- 공간 복잡도: O(1) — Map의 키가 0~59로 고정 크기
여담
hash를 사용해야겠다는 사실은 잘 떠오르는데, 어떻게 써야 하는지 한번에 떠오르질 않아서 풀이 시간이 너무 오래 걸린다 ㅠㅠ