Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions jugwang/week8/BOJ10867.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
중복 빼고 정렬하기 (백준 10867번)

- 시간 복잡도: O(N log N)
- N: 입력 숫자의 개수
- Stream의 sorted() 메서드는 Timsort를 사용하므로 O(N log N)
- distinct() 메서드는 O(N)이지만 정렬이 지배적이므로 전체 시간 복잡도는 O(N log N)

- 풀이
1. N개의 정수를 입력받아 중복을 제거하고 오름차순으로 정렬하는 문제
2. Java 8의 Stream API를 활용하여 간결하게 구현
3. sorted()로 정렬 후 distinct()로 중복 제거하거나, distinct() 후 sorted() 모두 가능
4. forEach()로 결과를 공백으로 구분하여 출력
*/

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class BOJ10867 {
public static void main(String[] args) {
// Test cases
int[] inputCounts = {10};
int[][] inputNumbers = {
{1, 4, 2, 3, 1, 4, 2, 3, 1, 2}
};
int[][] expectedResults = {
{1, 2, 3, 4}
};

for (int t = 0; t < inputCounts.length; t++) {
System.out.println("--- Test Case " + (t + 1) + " ---");

int count = inputCounts[t];
List<Integer> nums = new ArrayList<>();

System.out.println("Input count: " + count);
System.out.print("Input numbers: ");
for (int num : inputNumbers[t]) {
nums.add(num);
System.out.print(num + " ");
}
System.out.println();

List<Integer> result = solution(nums);

System.out.print("Result: ");
for (int i = 0; i < result.size(); i++) {
System.out.print(result.get(i));
if (i < result.size() - 1) System.out.print(" ");
}
System.out.println();

System.out.print("Expected: ");
for (int i = 0; i < expectedResults[t].length; i++) {
System.out.print(expectedResults[t][i]);
if (i < expectedResults[t].length - 1) System.out.print(" ");
}
System.out.println();

boolean isSuccess = result.size() == expectedResults[t].length;
if (isSuccess) {
for (int i = 0; i < result.size(); i++) {
if (!result.get(i).equals(expectedResults[t][i])) {
isSuccess = false;
break;
}
}
}

System.out.println(isSuccess ? ">>> SUCCESS" : ">>> FAILURE");
System.out.println();
}
}

public static List<Integer> solution(List<Integer> arr) {
return arr.stream()
.sorted() // 정렬 후
.distinct() // 중복 제거
.collect(Collectors.toList()); // 리스트로 수집
}
}
103 changes: 103 additions & 0 deletions jugwang/week8/BOJ1449.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
수리공 항승 (백준 1449번)

- 시간 복잡도: O(N log N)
- N: 물이 새는 곳의 개수
- 정렬이 필요하므로 O(N log N)
- 그 후 순차적으로 처리하므로 O(N)
- 전체적으로 O(N log N)

- 풀이
1. 물이 새는 곳을 효율적으로 수리하기 위해 테이프를 최소한으로 사용하는 문제
2. 그리디 알고리즘: 물이 새는 위치를 정렬한 후, 왼쪽부터 차례로 테이프를 붙임
3. 각 테이프는 길이 L만큼 커버할 수 있고, 물이 새는 위치 기준으로 ±0.5 범위를 덮어야 함
4. 현재 테이프가 커버하지 못하는 위치가 나오면 새로운 테이프 사용
5. 테이프의 시작점은 물이 새는 위치에서 0.5를 뺀 지점부터 시작하여 최대한 효율적으로 배치
*/

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

public class BOJ1449 {
public static void main(String[] args) {
// Test cases
int[] leakCounts = {4, 4, 3};
double[] tapeLengths = {2, 3, 1};
int[][] leakPositions = {
{1, 2, 100, 101},
{1, 2, 3, 4},
{3, 2, 1}
};
int[] expectedResults = {2, 2, 3};

for (int t = 0; t < leakCounts.length; t++) {
System.out.println("--- Test Case " + (t + 1) + " ---");

int num = leakCounts[t];
double length = tapeLengths[t];

System.out.println("Number of leaks: " + num + ", Tape length: " + length);
System.out.print("Leak positions: ");

List<double[]> leaks = Arrays.stream(leakPositions[t])
.mapToDouble(i -> (double)i)
.mapToObj(i -> new double[]{i})
.collect(Collectors.toList());

for (int pos : leakPositions[t]) {
System.out.print(pos + " ");
}
System.out.println();

// 정렬된 순서 보여주기
double[] sortedPositions = Arrays.stream(leakPositions[t])
.mapToDouble(i -> (double)i)
.sorted()
.toArray();
System.out.print("Sorted positions: ");
for (double pos : sortedPositions) {
System.out.print((int)pos + " ");
}
System.out.println();

int result = solution(leaks, length);

System.out.println("Result: " + result + " tapes needed");
System.out.println("Expected: " + expectedResults[t] + " tapes needed");

boolean isSuccess = (result == expectedResults[t]);
System.out.println(isSuccess ? ">>> SUCCESS" : ">>> FAILURE");
System.out.println();
}
}

public static int solution(List<double[]> arr, double length) {
// 물이 새는 위치 정렬
arr.sort(Comparator.comparingDouble(d -> d[0]));

// 초기 상태: 첫 번째 테이프 사용, 첫 번째 누수 위치에서 0.5를 뺀 지점부터 커버 시작
double[] initialState = new double[] {
1.0, // 테이프 개수
arr.get(0)[0] - 0.5 +length // 첫 번째 누수 위치에서 0.5를 뺀 지점부터 커버 시작
};

double[] ans = arr.stream()
.skip(1) // 첫 번째 누수 위치는 이미 처리했으므로 건너뜀
.reduce(initialState, ( state, leak) -> {
double count = state[0]; // 사용한 테이프 개수
double usingLength = state[1]; // 현재 테이프가 커버하는 최대 위치

// 테잎의 총 길이 만큼 커버 가능
// 테잎이 커버하는 범위에서 벗어나면 새 테잎 사용
if (leak[0] - 0.5 >= usingLength) {
count++; // 새 테잎 사용
usingLength = leak[0] - 0.5 + length;
}
// 현재 상태 반환
return new double[]{count, usingLength};
});
return (int)ans[0]; // 사용한 테이프 개수 반환
}
}
76 changes: 76 additions & 0 deletions jugwang/week8/BOJ18110.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
solved.ac 성공 (백준 18110번)

- 시간 복잡도: O(N log N)
- N: 의견의 개수
- 정렬이 필요하므로 O(N log N)
- Stream의 sorted() 메서드가 지배적인 시간 복잡도

- 풀이
1. solved.ac에서 문제 난이도를 결정하는 방식을 구현하는 문제
2. 전체 의견 수의 15%에 해당하는 상위, 하위 의견을 제외 (반올림 적용)
3. 나머지 의견들의 평균을 구하여 반올림한 값이 최종 난이도
4. 의견이 0개인 경우 난이도는 0
5. Stream API를 활용하여 정렬, 상하위 제외, 평균 계산을 연쇄적으로 처리
*/

import java.util.ArrayList;

class Solution {
public int solution(ArrayList<Integer> arr) {

int cut = (int)(Math.round(arr.size() * 0.15)); // 상하위 15% 컷

double ans = arr.stream()
.sorted() // 정렬
.skip(cut) // 상위 15% 제외
.limit(arr.size() - 2 * cut) // 하위 15% 제외
.mapToInt(Integer::intValue) // 정수형 스트림으로 변환
.average() // 평균 계산
.orElse(0.0); // 의견이 없으면 0.0 반환

return (int)Math.round(ans); // 반올림하여 정수로 반환
}
}

public class BOJ18110 {
public static void main(String[] args) {
// Test cases
int[] inputCounts = {5, 10};
int[][] opinions = {
{1, 5, 5, 7, 8},
{1, 13, 12, 15, 3, 16, 13, 12, 14, 15}
};
int[] expectedResults = {6, 13};

for (int t = 0; t < inputCounts.length; t++) {
System.out.println("--- Test Case " + (t + 1) + " ---");

int count = inputCounts[t];
ArrayList<Integer> nums = new ArrayList<>();

System.out.println("Number of opinions: " + count);
System.out.print("Opinions: ");
for (int opinion : opinions[t]) {
nums.add(opinion);
System.out.print(opinion + " ");
}
System.out.println();

// 15% 계산 설명
double percentage = count * 0.15;
int cut = (int)(Math.round(percentage));
System.out.println("15% of " + count + " = " + percentage + " → cut " + cut + " from each end");

Solution solved = new Solution();
int result = solved.solution(nums);

System.out.println("Result: " + result);
System.out.println("Expected: " + expectedResults[t]);

boolean isSuccess = (result == expectedResults[t]);
System.out.println(isSuccess ? ">>> SUCCESS" : ">>> FAILURE");
System.out.println();
}
}
}
106 changes: 106 additions & 0 deletions jugwang/week8/BOJ2170.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
선 긋기 (백준 2170번)

- 시간 복잡도: O(N log N)
- N: 선분의 개수
- 선분들을 시작점 기준으로 정렬하는 과정이 O(N log N)
- 그 후 순차적으로 병합하는 과정은 O(N)
- 전체적으로 O(N log N)

- 풀이
1. 여러 선분들이 주어졌을 때, 이들을 하나의 수직선에 그었을 때의 총 길이를 구하는 문제
2. 겹치는 선분들은 하나로 합쳐져야 하므로 구간 병합(Interval Merge) 알고리즘 사용
3. 선분들을 시작점 기준으로 정렬한 후, 순차적으로 병합
4. 현재 선분이 이전 선분과 겹치면 병합하고, 그렇지 않으면 새로운 구간으로 처리
5. 최종적으로 병합된 모든 구간의 길이를 합산
*/
import java.util.ArrayList;
import java.util.List;

public class BOJ2170 {
public static void main(String[] args) {
// Test cases
int[] lineCounts = {4};
int[][][] lines = {
{{1, 3}, {2, 5}, {3, 5}, {6, 7}}
};
int[] expectedResults = {5};

for (int t = 0; t < lineCounts.length; t++) {
System.out.println("--- Test Case " + (t + 1) + " ---");

int lineCount = lineCounts[t];
List<int[]> nums = new ArrayList<>();

System.out.println("Number of lines: " + lineCount);
System.out.println("Lines:");
for (int[] line : lines[t]) {
nums.add(new int[]{line[0], line[1]});
System.out.println(" [" + line[0] + ", " + line[1] + "] (length: " + (line[1] - line[0]) + ")");
}

// 정렬된 순서 보여주기
List<int[]> sortedLines = new ArrayList<>(nums);
sortedLines.sort((arr1, arr2) -> Integer.compare(arr1[0], arr2[0]));
System.out.println("Sorted by start point:");
for (int[] line : sortedLines) {
System.out.println(" [" + line[0] + ", " + line[1] + "]");
}

int result = solution(nums);

System.out.println("Result: " + result + " (total length after merging overlapping lines)");
System.out.println("Expected: " + expectedResults[t]);

// 병합 과정 설명
System.out.println("Merge process:");
System.out.println(" [1,3] and [2,5] overlap → merge to [1,5] (length: 4)");
System.out.println(" [1,5] and [3,5] overlap → stay [1,5] (length: 4)");
System.out.println(" [1,5] and [6,7] don't overlap → separate [6,7] (length: 1)");
System.out.println(" Total: 4 + 1 = 5");

boolean isSuccess = (result == expectedResults[t]);
System.out.println(isSuccess ? ">>> SUCCESS" : ">>> FAILURE");
System.out.println();
}
}

public static int solution(List<int[]> arr) {
int[] ans = arr.stream()
.sorted((arr1, arr2) -> Integer.compare(arr1[0], arr2[0])) // 시작점 기준 정렬
.reduce(new int[] {arr.get(0)[0], arr.get(0)[1], 0, 0}, (state, step) -> {
int start; // 현재 병합된 구간의 시작점
int end; // 현재 병합된 구간의 끝점
int length = state[2]; // 현재 병합된 구간의 길이
int sum = state[3]; // 지금까지의 총 길이 합

// 현재 선분이 이전 병합된 구간과 겹치는지 확인
if(state[0] <=step[0] && step[0] <= state[1]) {
if(state[0] <=step[1] && step[1] <= state[1]) {
end = state[1]; // 완전히 포함되는 경우
} else {
end = step[1]; // 일부만 겹치는 경우
}

start = state[0]; // 시작점은 이전 구간의 시작점 유지
length = Math.abs(end - start); // 병합된 구간의 길이 갱신
} else {
if(state[0] <=step[1] && step[1] <= state[1]) { // 이전 구간이 현재 선분을 포함하는 경우
end = state[1]; // 완전히 포함되는 경우
} else {
end = step[1]; // 겹치지 않는 경우

}

start = step[0]; // 시작점은 현재 선분의 시작점으로 갱신
sum += length; // 이전까지의 길이 합산
length = Math.abs(end - start); // 현재 구간의 길이 갱신
}

return new int[] {start, end, length, sum}; // [시작점, 끝점, 현재 구간 길이, 지금까지 총 길이]
});


return ans[3]+ans[2];
}
}
Loading