문제 - 가장 많이 겹치는 구간 (기본문제)
가장 많이 겹치는 구간 설명 | 코드트리
가장 많이 겹치는 구간의 요구사항을 정확히 분석하고, 적절한 알고리즘을 고안해 두 번째 단계 중급 문제를 해결해보세요.
www.codetree.ai
public class Main {
static StreamTokenizer sst = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static int read() throws IOException{
sst.nextToken();
return (int) sst.nval;
}
public static void main(String[] args) throws IOException{
int N = read();
int[][] pos = new int[2*N][2];
for(int i = 0; i<N; i++){
int a = read();
int b = read();
pos[2*i] = new int[]{a, 1};
pos[2*i+1] = new int[]{b, -1};
}
Arrays.sort(pos, Comparator.comparingInt(a->a[0]));
int cnt = 0;
int ans = 0;
for(int i = 0; i<2*N; i++){
cnt += pos[i][1];
ans = Math.max(ans, cnt);
}
System.out.print(ans);
}
}
풀이 설명
선분의 양 끝 점의 위치가 차례로 주어졌을 때 가장 많이 중복되는 곳의 선분 갯수를 구하는 문제이다.
이벤트 스위핑 기법으로 풀이한다.
먼저 입력을 받을 때 데이터가 아닌 이벤트 기준으로 입력을 받는다.
-> 이벤트란 선분이 시작됨. 선분이 끝남 이거 2개니까 pos는 2*N의 크기를 가진다.
선분이 시작될 때 +1, 선분이 끝날때 -1로 입력을 받고
여기서는 시작과 끝이 닿았을 때 중복이 아닌 문제이므로 그냥 a,b 증감없이 받는다.
그리고 이벤트 발생 지점을 기준으로 오름차순으로 이벤트 배열을 정렬하고
차례로 보며 이벤트 값을 cnt에 더해준다.
-> 이때의 순간 최댓값을 구하면 정답
문제 - 서로 다른 구간 갯수
서로 다른 구간의 수 설명 | 코드트리
서로 다른 구간의 수의 요구사항을 정확히 분석하고, 적절한 알고리즘을 고안해 두 번째 단계 중급 문제를 해결해보세요.
www.codetree.ai
public class Main {
static StreamTokenizer sst = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static int read() throws IOException{
sst.nextToken();
return (int) sst.nval;
}
public static void main(String[] args) throws IOException{
int N = read();
int[][] pos = new int[2*N][2];
for(int i = 0; i<N; i++){
int a = read();
int b = read();
pos[2*i] = new int[]{a,1};
pos[2*i+1] = new int[]{b,-1};
}
Arrays.sort(pos, Comparator.comparingInt(a->a[0]));
int cnt = 0;
int prev = 0;
int ans = 0;
for(int i = 0; i<2*N; i++){
cnt += pos[i][1];
if(prev == 0 && cnt == 1){
ans++;
}
prev = cnt;
}
System.out.print(ans);
}
}
풀이 설명
이벤트 단위로 입력을 받고 정점과 정점의 끝이 포함으로 세지 않으므로 그냥 a,b로 받음.
선분들이 주어지고 겹친 선분끼리는 합친다고 했을때 이 연산을 끝까지 반복한 결과의 선분 덩어리의 총 갯수 구하기
-> 이벤트 델타값 기준으로 0에서 1로 변화할때 한 덩어리의 시작이므로 이거 갯수 세 주기
문제 - 겹치는 선분들
https://www.codetree.ai/ko/trails/complete/curated-cards/challenge-overlapping-lines/description
겹치는 선분들 설명 | 코드트리
겹치는 선분들의 요구사항을 정확히 분석하고, 적절한 알고리즘을 고안해 두 번째 단계 중급 문제를 해결해보세요.
www.codetree.ai
public class Main {
static StreamTokenizer sst = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static int read() throws IOException{
sst.nextToken();
return (int) sst.nval;
}
static char rc() throws IOException{
sst.nextToken();
return (char) sst.sval.charAt(0);
}
public static void main(String[] args) throws IOException{
int N = read();
int K = read();
int[][] pos = new int[2*N][2];
int prev = 0;
for(int i = 0; i<N; i++){
int a = read();
char cmd = rc();
if(cmd == 'R'){
pos[2*i] = new int[]{prev, 1};
pos[2*i+1] = new int[]{prev+a, -1};
prev += a;
}
else{
pos[2*i] = new int[]{prev-a, 1};
pos[2*i+1] = new int[]{prev, -1};
prev -= a;
}
}
Arrays.sort(pos, Comparator.comparingInt(a->a[0]));
int cnt = 0;
long sum = 0;
// 길이는 항상 현재 이벤트 ~ 다음 이벤트 에서 발생함
for(int i = 0; i<2*N-1; i++){
cnt += pos[i][1];
int len = pos[i+1][0] - pos[i][0];
if(cnt >= K){
sum += len;
}
}
System.out.print(sum);
}
}
풀이 설명
문제 입력에서 num, L or R로 주어지는데 이는 맨 처음은 원점에서 시작해서 num 만큼 left or Right로 선을 그리고
그다음 마지막 위치에서 시작해서 또 num 만큼 방향대로 그리는 것임
-> L = prev-a ~ prev, R = prev ~ prev+a를 기준으로 이벤트 델타값을 입력받음
이벤트 발생 시점을 기준으로 오름차순 정렬하고
K개 이상의 선분이 겹치는 곳의 길이를 구하는 문제인데
길이는 항상 다음 이벤트 시점이 존재할 때 다음 이벤트 시점 - 현재 이벤트 시점으로 구해짐
그러면 겹쳐진 갯수는 cnt에 이벤트 델타값을 누적해서 구하고 길이 구한것을 cnt가 K 이상일때 누적하면 답
문제 - 합쳐진 덩어리의 구간 합
https://www.codetree.ai/ko/trails/complete/curated-cards/challenge-sum-of-interval-sizes/description
구간 크기의 합 설명 | 코드트리
구간 크기의 합의 요구사항을 정확히 분석하고, 적절한 알고리즘을 고안해 두 번째 단계 중급 문제를 해결해보세요.
www.codetree.ai
public class Main {
static StreamTokenizer sst = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static int read() throws IOException{
sst.nextToken();
return (int) sst.nval;
}
public static void main(String[] args) throws IOException{
int N = read();
int[][] pos = new int[2*N][2];
for(int i = 0; i<N; i++){
int a = read();
int b = read();
pos[2*i] = new int[]{a,1};
pos[2*i+1] = new int[]{b,-1};
}
Arrays.sort(pos, Comparator.comparingInt(a->a[0]));
int cnt = 0;
int prev = 0;
int s = 0;
long ans = 0;
for(int i = 0; i<2*N; i++){
cnt += pos[i][1];
if(prev == 0 && cnt == 1)
s = pos[i][0];
if(prev == 1 && cnt == 0){
ans += pos[i][0] - s;
}
prev = cnt;
}
System.out.print(ans);
}
}
풀이 설명
모든 겹쳐진 선분을 합하는 연산을 끝까지 진행했을때 한 덩어리의 크기들의 합을 구하기
한 덩어리의 시작 부분은 cnt의 변화가 0->1 일때 시작이고 1->0일때 끝임
-> 시작 부분에서 현재 이벤트의 발생 지점이 start이고
끝 부분에서 현재 이벤트의 발생 지점이 end이므로 pos[i][0] - s를 누적하면 답임.
문제 - 호텔 방 관리(PriorityQueue)
https://www.codetree.ai/ko/trails/complete/curated-cards/test-reserve-hotel/description
호텔 예약 설명 | 코드트리
호텔 예약의 요구사항을 정확히 분석하고, 적절한 알고리즘을 고안해 두 번째 단계 중급 문제를 해결해보세요.
www.codetree.ai
public class Main {
static StreamTokenizer sst = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static int read() throws IOException{
sst.nextToken();
return (int) sst.nval;
}
public static void main(String[] args) throws IOException{
int N = read();
// 이벤트 시각, 델타값, 사람 번호
int[][] E = new int[2*N][3];
for(int i = 0; i<N; i++){
int a = read();
int b = read();
E[2*i] = new int[]{a, 1, i+1};
E[2*i+1] = new int[]{b, -1, i+1};
}
Arrays.sort(E, (a,b)->{
if(a[0] != b[0])
return a[0] - b[0];
return b[1] - a[1];
});
int nextRoom = 0;
// 비어있는 방 번호
PriorityQueue<Integer> q =new PriorityQueue<>();
// i번 사람이 val 방 쓰는중
int[] using = new int[N+1];
Set<Integer> ans = new HashSet<>();
for(int i= 0; i<2*N; i++){
// 입실 발생
if(E[i][1] == 1){
int nRoom = 0;
if(q.isEmpty()){
nRoom = nextRoom++;
}
else{
nRoom = q.poll();
}
// 사람을 방에 배정
using[E[i][2]] = nRoom;
ans.add(nRoom);
}
// 퇴실 발생
else{
q.add(using[E[i][2]]);
}
}
System.out.print(ans.size());
}
}
사고의 흐름
N명의 사람의 입실과 퇴실 시각 기록이 주어질 때 이 사람들을 모두 한 호텔에 수용하기 위한 최소 호텔 방 수는 몇일지 계산
이벤트 단위 배열로 나누어 [ 이벤트 발생 시각, 델타 값(입실, 퇴실 구분용), 사람 번호 ] 로 저장함.
-> 발생 시각 오름차순, 델타 값 내림차순으로 정렬함
-> 그래야 같은 날 입실 이벤트를 먼저 처리하게 됨.
풀이
사용자가 쓰고 남은 여유 방 중 방 번호가 가장 작은게 먼저 사용될 방 번호를 관리하는 우선순위 큐 하나를 두고,
i번 사람이 val 값 방 번호를 현재 점유 중임을 나타내는 N+1 짜리 배열과
중복되지 않는 방번호 Set(answer)를 정의함
1) 입실 이벤트 발생
-> 현재 잔여 빈방이 없음 : nextRoom이 배정될 방이고 이후 nextRoom += 1
-> 현재 잔여 빈방이 있음 : 우선순위 큐에서 하나 꺼내서 배정될 방으로 선정함
using[ 현재 사람 번호 ] = 배정될 방 번호
2) 퇴실 이벤트 발생
-> 잔여 빈 방이 발생하므로 우선순위 큐에 using [ 현재 사람 번호 ] 의 값을 넣는다.
1, 2번을 모든 이벤트 단위 시각에 대해서 반복하고
using 배열에 방 번호가 갱신될 때마다 Set에 넣어 중복되지 않게 어떤 방들이 사용되었는지 기록하면
입/퇴실 기록에 따른 모든 사용자를 수용하기 위한 최소 호텔 방 수는 Set.size() 이다.
문제 - 선분 합 최대화 (다시 보기, 집합 관리)
최대 길이를 위해 선분 제거하기 설명 | 코드트리
최대 길이를 위해 선분 제거하기의 요구사항을 정확히 분석하고, 적절한 알고리즘을 고안해 두 번째 단계 중급 문제를 해결해보세요.
www.codetree.ai
public class Main {
static StreamTokenizer sst = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static int read() throws IOException{
sst.nextToken();
return (int) sst.nval;
}
public static void main(String[] args) throws IOException{
int N = read();
// etime, delta, idx
int[][] E = new int[2*N][3];
for(int i = 0; i<N; i++){
int a = read();
int b = read();
E[2*i] = new int[]{a,1,i};
E[2*i+1] = new int[]{b,-1,i};
}
Arrays.sort(E, (a,b)->{
if(a[0]!=b[0])
return a[0] - b[0];
return b[1] - a[1];
});
int cnt = 0;
int[] lens = new int[N];
int total = 0;
// cnt = 1 활성화 된 선분 자기 하나
// cnt > 0 선분 활성화되어 있음 len 전부 더하면 합집합 길이 됨.
// -> cnt로만으로는 어떤 선분에 이어야할지 불명확함
TreeSet<Integer> ts = new TreeSet<>();
for(int i = 0; i<2*N-1; i++){
int len = E[i+1][0] - E[i][0];
cnt += E[i][1];
// 시작이벤트는 활성화된 선분으로 등록
if(E[i][1] == 1)
ts.add(E[i][2]);
// 끝이벤트는 활성화된 선분에서 빼기
else
ts.remove(E[i][2]);
if(cnt != 0)
total += len;
if(cnt == 1){
int idx = ts.iterator().next();
lens[idx] += len;
}
}
int ans = 0;
for(int i = 0; i<N; i++){
ans = Math.max(ans, total - lens[i]);
}
System.out.print(ans);
}
}
사고의 흐름 및 풀이
문제 조건처럼 하나의 선분만 제외해서 전체 선분의 길이 합집합을 가장 크게 하려면 그 선분만 덮고 있었던 길이를 빼면 된다.
그렇다면 이벤트 스위핑에서 cnt는 현재 활성화된 선분의 수를 의미하므로
cnt가 1일때 다음 이벤트 - 지금 이벤트 를 더하면 되는데
여기서 하나의 스위핑에서 여러개의 하나만 살아남은 선분이 있을 수 있다.
-> TreeSet을 이용해서 cnt가 1일때 iterator().next()로 그 선분의 idx를 찾아 lens 배열을 갱신한다.
TreeSet은 현재 활성화된 선분이므로 시작 이벤트에서 add하고 끝 이벤트에서 remove한다.
전체 합집합의 경우 선분이 1개 이상 활성화 되어 있을때 len을 합산하면 중복 없이 전체 선분이 덮는 길이를 구할 수 있다.
'공부 > 알고리즘' 카테고리의 다른 글
| [코드트리] - Prefix & Suffix (0) | 2026.07.30 |
|---|---|
| [코드트리] - 최단경로, 플로이드 (1) | 2026.07.15 |
| [코드트리] - 그래프 이론, 다익스트라 (0) | 2026.07.11 |
| [코드트리] 10 - DP, 비트마스킹 (0) | 2026.07.02 |
| [코드트리] 9 - DP, 구간합 DP (0) | 2026.07.01 |