diff --git a/jugwang/week8/BOJ10867.java b/jugwang/week8/BOJ10867.java new file mode 100644 index 0000000..43894e6 --- /dev/null +++ b/jugwang/week8/BOJ10867.java @@ -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 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 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 solution(List arr) { + return arr.stream() + .sorted() // 정렬 후 + .distinct() // 중복 제거 + .collect(Collectors.toList()); // 리스트로 수집 + } +} \ No newline at end of file diff --git a/jugwang/week8/BOJ1449.java b/jugwang/week8/BOJ1449.java new file mode 100644 index 0000000..9f0381b --- /dev/null +++ b/jugwang/week8/BOJ1449.java @@ -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 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 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]; // 사용한 테이프 개수 반환 + } +} \ No newline at end of file diff --git a/jugwang/week8/BOJ18110.java b/jugwang/week8/BOJ18110.java new file mode 100644 index 0000000..3cecfce --- /dev/null +++ b/jugwang/week8/BOJ18110.java @@ -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 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 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(); + } + } +} \ No newline at end of file diff --git a/jugwang/week8/BOJ2170.java b/jugwang/week8/BOJ2170.java new file mode 100644 index 0000000..f164dc0 --- /dev/null +++ b/jugwang/week8/BOJ2170.java @@ -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 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 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 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]; + } +} \ No newline at end of file diff --git a/jugwang/week8/BOJ2212.java b/jugwang/week8/BOJ2212.java new file mode 100644 index 0000000..a76c00d --- /dev/null +++ b/jugwang/week8/BOJ2212.java @@ -0,0 +1,89 @@ +/* +센서 (백준 2212번) + +- 시간 복잡도: O(N log N) + - N: 센서의 개수 + - 중복 제거 및 정렬이 필요하므로 O(N log N) + - 거리 계산 및 정렬: O(N log N) + - 전체적으로 O(N log N) + +- 풀이 + 1. N개의 센서와 K개의 집중국을 이용하여 모든 센서를 커버하는 문제 + 2. 집중국의 수신 가능 영역의 길이 합을 최소화하는 그리디 알고리즘 + 3. 센서들을 정렬한 후, 인접한 센서 간의 거리를 계산 + 4. K개의 집중국으로 나누려면 (K-1)개의 가장 긴 거리를 제거 + 5. 남은 거리들의 합이 최소 수신 가능 영역의 길이 +*/ + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class BOJ2212 { + public static void main(String[] args) { + // Test cases + int[] sensorCounts = {6, 10}; + int[] centerCounts = {2, 5}; + int[][] sensorPositions = { + {1, 6, 9, 3, 6, 7}, + {20, 3, 14, 6, 7, 8, 18, 10, 12, 15} + }; + int[] expectedResults = {5, 7}; + + for (int t = 0; t < sensorCounts.length; t++) { + System.out.println("--- Test Case " + (t + 1) + " ---"); + + int sensorCount = sensorCounts[t]; + int centerCount = centerCounts[t]; + + System.out.println("Sensors: " + sensorCount + ", Centers: " + centerCount); + System.out.print("Sensor positions: "); + for (int pos : sensorPositions[t]) { + System.out.print(pos + " "); + } + System.out.println(); + + List centers = Arrays.stream(sensorPositions[t]) + .boxed() + .distinct() + .sorted() + .collect(Collectors.toList()); + + System.out.print("Unique sorted positions: "); + for (int pos : centers) { + System.out.print(pos + " "); + } + System.out.println(); + + int result = solution(centers, centerCount); + + 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(); + } + } + + public static int solution(List arr, int center) { + // 집중국의 수가 센서의 수보다 많거나 같으면 모든 센서를 개별적으로 커버 가능 + if (center >= arr.size()) return 0; + + // 인접한 센서 간의 거리 계산 + ArrayList newArr = new ArrayList<>(); + + // 인접한 센서 간의 거리 계산 + for (int i=0; i