├── README.md ├── assets └── java_image.jpg └── solution ├── 01.java ├── 02.java ├── 03.java ├── 04.java ├── 05.java ├── 06.java ├── 07.java ├── 08.java ├── 09.java ├── 10.java ├── 11.java ├── 12.java ├── 13.java ├── 14.java ├── 15.java ├── 16.java ├── 17.java ├── 18.java ├── 19.java ├── 20.java ├── 21.java ├── 22.java ├── 23.java ├── 24.java ├── 25.java ├── 26.java ├── 27.java ├── 28.java ├── 29.java ├── 30.java ├── 31.java ├── 32.java ├── 33.java ├── 34.java ├── 35.java ├── 36.java ├── 37.java ├── 38.java ├── 39.java ├── 40.java ├── 41.java ├── 42.java ├── 43.java ├── 44.java ├── 45.java ├── 46.java ├── 47.java ├── 48.java ├── 49.java ├── 50.java ├── 51.java ├── 52.java ├── 53.java ├── 54.java ├── 55.java ├── 56.java ├── 57.java ├── 58.java ├── 59.java ├── 60.java ├── 61.java ├── 62.java ├── 63.java ├── 64.java ├── 65.java ├── 66.java ├── 67.java ├── 68.java ├── 69.java ├── 70.java ├── 71.java ├── 72.java ├── 73.java ├── 74.java ├── 75.java ├── 76.java ├── 77.java ├── 78.java ├── 79.java ├── 80.java ├── 81.java ├── 82.java ├── 83.java ├── 84.java ├── 85.java ├── 86.java ├── 87.java ├── 88.java ├── 89.java ├── 90.java ├── 91.java ├── 92.java ├── 93.java ├── 94.java ├── 95.java ├── 96.java └── 97.java /README.md: -------------------------------------------------------------------------------- 1 | # 코딩 테스트 합격자 되기(자바 편) 2 | - 프로그래머스에서 엄선한 기출 문제에 대한 상세한 풀이 제공 3 | - 들고 다닐 수 있는 요약 노트 제공 4 | - 실전 문제 위주로 출제된 기출 문제 5회분 제공(회당 3 문제) 5 | 6 | 7 | ## 📖 도서 구매 링크 8 | - Yes24 : https://www.yes24.com/Product/Goods/125183948 9 | - 교보문고 : https://product.kyobobook.co.kr/detail/S000212576322 10 | - 알라딘 : https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=335109613 11 | - 리디북스(Ebook) : https://ridibooks.com/books/4547000036 12 | 13 | image 14 | 15 | # 정오표 16 | [클릭](https://docs.google.com/spreadsheets/d/16ZWyC2xlylfsGBdyt2YMT8ogpukNh7sXsHrfx5qQuFk/edit#gid=0) 17 | 18 | # 책소개 19 | ![image](https://github.com/retrogemHK/codingtest_java/blob/main/assets/java_image.jpg) 20 | 21 | 22 | # 진행중인 이벤트 23 | | Event | 세부내용 |기간 | 24 | | ---------- | ---------------------------------------------- |---------------------------------------------- | 25 | |코딩테스트 스터디 |[참여방법 및 스터디 세부사항](https://cafe.naver.com/dremdeveloper/948) | 상시 | 26 | 27 | 28 | 29 | # 코딩테스트 소통공간(저자가 직접운영) 30 | | Title | Description | 31 | | ---------- | ---------------------------------------------- | 32 | |카카오톡 오픈채팅 |[클릭](https://open.kakao.com/o/gQOVhU3f) | 33 | 34 | # 연락처 35 | - 해당 코드들에 대해 문의사항이 있거나, 연락이 필요한 경우 아래 참조 36 | 37 | | Title | Description | 38 | |-------------------|-------------------------------------------------| 39 | | Cafe | http://cafe.naver.com/dremdeveloper | 40 | | Business Mail | kylados@naver.com | 41 | | Codingtest Python | https://github.com/dremdeveloper/codingtest_python | 42 | | Codingtest CPP | https://github.com/dremdeveloper/codingtest_cpp | 43 | # 폴더 구조 44 | - 깃 허브의 폴더 구조에 대한 설명 45 | 46 | | Title | Description | 47 | | ---------- | ---------------------------------------------- | 48 | | errorcode | 구현시 자주 발생하는 에러메시지 | 49 | | mistake | 구현시 자주 실수할수 있는 사항 | 50 | | performance | 비슷한 동작을 하는데 시간복잡도가 다른 경우에 대한 시간비교 | 51 | | reference | 코딩테스트에서 많이 사용하는 문법 | 52 | | solution | 책에 있는 문제에 대한 해설 | 53 | | Algorithm_with_DataStructure | 코딩테스트에 등장하는 알고리즘과 자료구조 | 54 | -------------------------------------------------------------------------------- /assets/java_image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retrogemHK/codingtest_java/755a881de4d50479150bcffdee502d98a8503707/assets/java_image.jpg -------------------------------------------------------------------------------- /solution/01.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | public class Solution { 4 | 5 | public static void main(String[] args) { 6 | System.out.println(Arrays.toString(solution(new int[]{1, -5, 2, 4, 3}))); 7 | System.out.println(Arrays.toString(solution(new int[]{2, 1, 1, 3, 2, 5, 4}))); 8 | System.out.println(Arrays.toString(solution(new int[]{6, 1, 7}))); 9 | } 10 | 11 | // 이 부분을 변경해서 실행해보세요. 12 | private static int[] solution(int[] arr) { 13 | Arrays.sort(arr); 14 | return arr; 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /solution/02.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | import java.util.Collections; 3 | 4 | public class Solution { 5 | 6 | public static void main(String[] args) { 7 | System.out.println(Arrays.toString(solution(new int[]{4, 2, 2, 1, 3, 4}))); 8 | System.out.println(Arrays.toString(solution(new int[]{2, 1, 1, 3, 2, 5, 4}))); 9 | } 10 | 11 | // 이 부분을 변경해서 실행해보세요. 12 | private static int[] solution(int[] arr) { 13 | Integer[] result = Arrays.stream(arr).boxed().distinct().toArray(Integer[]::new); // ❶ 중복값 제거 14 | Arrays.sort(result, Collections.reverseOrder()); // ❷ 내림차순 정렬 15 | return Arrays.stream(result).mapToInt(Integer::intValue).toArray(); // int형 배열로 변경 후 반환 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /solution/03.java: -------------------------------------------------------------------------------- 1 | import java.util.HashSet; 2 | 3 | public class Solution { 4 | 5 | public static int[] solution(int[] numbers) { 6 | HashSet set = new HashSet<>(); // ❶ 중복 값 제거를 위한 해쉬셋 생성 7 | // ❷ 두 수를 선택하는 모든 경우의 수를 반복문으로 구함 8 | for (int i = 0; i < numbers.length - 1; i++) { 9 | for (int j = i + 1; j < numbers.length; j++) { 10 | // ❸ 두 수를 더한 결과를 새로운 배열에 추가 11 | set.add(numbers[i] + numbers[j]); 12 | } 13 | } 14 | // ❹ 해쉬셋의 값을 오름차순 정렬하고 int[] 형태의 배열로 변환하여 반환 15 | return set.stream().sorted().mapToInt(Integer::intValue).toArray(); 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /solution/04.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.Arrays; 3 | 4 | public class Solution { 5 | 6 | public static int[] solution(int[] answers) { 7 | // ❶ 수포자들의 패턴 8 | int[][] pattern = { 9 | {1, 2, 3, 4, 5}, 10 | {2, 1, 2, 3, 2, 4, 2, 5}, 11 | {3, 3, 1, 1, 2, 2, 4, 4, 5, 5} 12 | }; 13 | // ❷ 수포자들의 점수를 저장할 배열 14 | int[] scores = new int[3]; 15 | 16 | // ❸ 각 수포자의 패턴과 정답이 얼마나 일치하는지 확인 17 | for (int i = 0; i < answers.length; i++) { 18 | for (int j = 0; j < pattern.length; j++) { 19 | if (answers[i] == pattern[j][i % pattern[j].length]) { 20 | scores[j]++; 21 | } 22 | } 23 | } 24 | // ❹ 가장 높은 점수 저장 25 | int maxScore = Arrays.stream(scores).max().getAsInt(); 26 | // ❺ 가장 높은 점수를 가진 수포자들의 번호를 찾아서 리스트에 담음 27 | ArrayList answer = new ArrayList<>(); 28 | for (int i = 0; i < scores.length; i++) { 29 | if (scores[i] == maxScore) { 30 | answer.add(i + 1); 31 | } 32 | } 33 | 34 | return answer.stream().mapToInt(Integer::intValue).toArray(); 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /solution/05.java: -------------------------------------------------------------------------------- 1 | public class Solution { 2 | 3 | public int[][] solution(int[][] arr1, int[][] arr2) { 4 | // ❶ 행렬 arr1과 arr2의 행과 열의 수 5 | int r1 = arr1.length; 6 | int c1 = arr1[0].length; 7 | int r2 = arr2.length; 8 | int c2 = arr2[0].length; 9 | 10 | // ❷ 결과를 저장할 2차원 배열 초기화 11 | int[][] answer = new int[r1][c2]; 12 | 13 | // ❸ 첫 번째 행렬 arr1의 각 행과 두 번째 행렬 arr2의 각 열에 대해 14 | for (int i = 0; i < r1; i++) { 15 | for (int j = 0; j < c2; j++) { 16 | // ❹ 두 행렬의 데이터를 곱해 결과 리스트에 더해줌 17 | for (int k = 0; k < c1; k++) { 18 | answer[i][j] += arr1[i][k] * arr2[k][j]; 19 | } 20 | } 21 | } 22 | 23 | return answer; 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /solution/06.java: -------------------------------------------------------------------------------- 1 | import java.util.HashMap; 2 | 3 | public class Solution { 4 | 5 | public int[] solution(int N, int[] stages) { 6 | // ❶ 스테이지별 도전자 수를 구함 7 | int[] challenger = new int[N + 2]; 8 | for (int i = 0; i < stages.length; i++) { 9 | challenger[stages[i]] += 1; 10 | } 11 | 12 | // ❷ 스테이지별 실패한 사용자 수 계산 13 | HashMap fails = new HashMap<>(); 14 | double total = stages.length; 15 | 16 | // ❸ 각 스테이지를 순회하며, 실패율 계산 17 | for (int i = 1; i <= N; i++) { 18 | if (challenger[i] == 0) { // ❹ 도전한 사람이 없는 경우, 실패율은 0 19 | fails.put(i, 0.); 20 | } 21 | else { 22 | fails.put(i, challenger[i] / total); // ❺ 실패율 구함 23 | total -= challenger[i]; // ❻ 다음 스테이지 실패율을 구하기 위해 현재 스테이지의 인원을 뺌 24 | } 25 | } 26 | 27 | // ❼ 실패율이 높은 스테이지부터 내림차순으로 정렬 28 | return fails.entrySet().stream().sorted((o1, o2) -> Double.compare(o2.getValue(), o1.getValue())).mapToInt(HashMap.Entry::getKey).toArray(); 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /solution/07.java: -------------------------------------------------------------------------------- 1 | import java.util.HashMap; 2 | import java.util.HashSet; 3 | 4 | public class Solution { 5 | 6 | // ❶ 좌표평면을 벗어나는지 체크하는 메소드 7 | private static boolean isValidMove(int nx, int ny) { 8 | return 0 <= nx && nx < 11 && 0 <= ny && ny < 11; 9 | } 10 | 11 | // ❷ 다음 좌표 결정을 위한 HashMap 생성 12 | private static final HashMap location = new HashMap<>(); 13 | 14 | private static void initLocation() { 15 | location.put('U', new int[]{0, 1}); 16 | location.put('D', new int[]{0, -1}); 17 | location.put('L', new int[]{-1, 0}); 18 | location.put('R', new int[]{1, 0}); 19 | } 20 | 21 | public int solution(String dirs) { 22 | initLocation(); 23 | int x = 5, y = 5; 24 | HashSet answer = new HashSet<>(); // ❸ 겹치는 좌표는 1개로 처리하기 위함 25 | // ❹ 주어진 명령어로 움직이면서 좌표 저장 26 | for (int i = 0; i < dirs.length(); i++) { 27 | int[] offset = location.get(dirs.charAt(i)); 28 | int nx = x + offset[0]; 29 | int ny = y + offset[1]; 30 | if (!isValidMove(nx, ny)) // ❺ 벗어난 좌표는 인정하지 않음 31 | continue; 32 | // ❻ A에서 B로 간 경우 B에서 A도 추가해야 함(총 경로의 개수는 방향성이 없음) 33 | answer.add(x + " " + y + " " + nx + " " + ny); 34 | answer.add(nx + " " + ny + " " + x + " " + y); 35 | // ❼ 좌표를 이동했으므로 업데이트 36 | x = nx; 37 | y = ny; 38 | } 39 | 40 | return answer.size() / 2; 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /solution/08.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayDeque; 2 | 3 | class Solution { 4 | 5 | private boolean solution(String s) { 6 | ArrayDeque stack = new ArrayDeque<>(); 7 | 8 | char[] a = s.toCharArray(); 9 | for (char c : a) { 10 | if (c == '(') { 11 | stack.push(c); 12 | } 13 | else { 14 | if(stack.isEmpty() || stack.pop() == c) 15 | return false; 16 | } 17 | } 18 | 19 | return stack.isEmpty(); 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /solution/09.java: -------------------------------------------------------------------------------- 1 | import java.util.Stack; 2 | 3 | public class Solution { 4 | 5 | public static void main(String[] args) { 6 | System.out.println(solution(10)); 7 | System.out.println(solution(27)); 8 | System.out.println(solution(12345)); 9 | } 10 | 11 | // 이 부분을 변경해서 실행해보세요. 12 | public static String solution(int decimal) { 13 | Stack stack = new Stack<>(); 14 | while (decimal > 0) { 15 | int remainder = decimal % 2; 16 | stack.push(remainder); 17 | decimal /= 2; 18 | } 19 | 20 | // String 의 + 연산은 시간복잡도 측면에서 성능이 좋지 않습니다. 21 | // 따라서 StringBuilder 를 사용했습니다. 22 | StringBuilder sb = new StringBuilder(); 23 | while (!stack.isEmpty()) { 24 | sb.append(stack.pop()); 25 | } 26 | 27 | return sb.toString(); 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /solution/10.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayDeque; 2 | import java.util.HashMap; 3 | 4 | class Solution { 5 | 6 | public static int solution(String s) { 7 | // ❶ 괄호 정보를 저장함. 코드를 간결하게 할 수 있음 8 | HashMap map = new HashMap<>(); 9 | map.put(')', '('); 10 | map.put('}', '{'); 11 | map.put(']', '['); 12 | 13 | int n = s.length(); // 원본 문자열의 길이 저장 14 | s += s; // 원본 문자열 뒤에 원본 문자열을 이어 붙여서 2번 나오도록 만들어줌 15 | 16 | int answer = 0; 17 | 18 | // ❷ 확인할 문자열의 시작 인덱스를 0 부터 n 까지 이동 19 | A:for (int i = 0; i < n; i++) { 20 | ArrayDeque stack = new ArrayDeque<>(); 21 | 22 | // ❸ i(시작 위치)부터 원본 문자열의 길이인 n개까지 올바른 괄호 문자열인지 확인 23 | for (int j = i; j < i + n; j++) { 24 | char c = s.charAt(j); 25 | // HashMap 안에 해당 key 가 없다면 열리는 괄호임 26 | if (!map.containsKey(c)) { 27 | stack.push(c); 28 | } 29 | else { 30 | // ❹ 짝이 맞지 않으면 내부 for문은 종료하고 for문 A로 이동 31 | if(stack.isEmpty() || !stack.pop().equals(map.get(c))) 32 | continue A; 33 | } 34 | } 35 | 36 | // ❺ 3에서 continue 되지 않았고, 스택이 비어있으면 올바른 괄호 문자열임 37 | if (stack.isEmpty()) 38 | answer++; 39 | } 40 | 41 | return answer; 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /solution/11.java: -------------------------------------------------------------------------------- 1 | import java.util.Stack; 2 | 3 | public class Solution { 4 | 5 | public int solution(String s) { 6 | Stack stack = new Stack<>(); 7 | for (int i = 0; i < s.length(); i++) { 8 | char c = s.charAt(i); 9 | // ❶ 스택이 비어 있지 않고, 현재 문자와 스택의 맨 위 문자가 같으면 10 | if (!stack.isEmpty() && stack.peek() == c) { 11 | stack.pop(); // ❷ 스택의 맨 위 문자 제거 12 | } 13 | else { 14 | stack.push(c); // ❸ 스택에 현재 문자 추가 15 | } 16 | } 17 | 18 | return stack.isEmpty() ? 1 : 0; // ❹ 스택이 비어 있으면 1, 그렇지 않으면 0 반환 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /solution/12.java: -------------------------------------------------------------------------------- 1 | import java.util.Stack; 2 | 3 | class Solution { 4 | 5 | public static int[] solution(int[] prices) { 6 | int n = prices.length; 7 | int[] answer = new int[n]; // ❶ 가격이 떨어지지 않은 기간을 저장할 배열 8 | 9 | // 스택(stack)을 사용해 이전 가격과 현재 가격 비교 10 | Stack stack = new Stack<>(); // ❷ 스택 생성 11 | stack.push(0); 12 | 13 | for (int i = 1; i < n; i++) { 14 | while (!stack.isEmpty() && prices[i] < prices[stack.peek()]) { 15 | // ❸ 가격이 떨어졌으므로 이전 가격의 기간 계산 16 | int j = stack.pop(); 17 | answer[j] = i - j; 18 | } 19 | stack.push(i); 20 | } 21 | 22 | // ❹ 스택에 남아 있는 가격들은 가격이 떨어지지 않은 경우 23 | while (!stack.isEmpty()) { 24 | int j = stack.pop(); 25 | answer[j] = n - 1 - j; 26 | } 27 | 28 | return answer; 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /solution/13.java: -------------------------------------------------------------------------------- 1 | import java.util.Stack; 2 | 3 | public class Solution { 4 | 5 | public int solution(int[][] board, int[] moves) { 6 | // ❶ 각 열에 대한 스택을 생성합니다. 7 | Stack[] lanes = new Stack[board.length]; 8 | for (int i = 0; i < lanes.length; i++) { 9 | lanes[i] = new Stack<>(); 10 | } 11 | 12 | // ❷ board를 역순으로 탐색하며, 각 열의 인형을 lanes에 추가합니다. 13 | for (int i = board.length - 1; i >= 0; i--) { 14 | for (int j = 0; j < board[i].length; j++) { 15 | if (board[i][j] > 0) { 16 | lanes[j].push(board[i][j]); 17 | } 18 | } 19 | } 20 | 21 | // ❸ 인형을 담을 bucket을 생성합니다. 22 | Stack bucket = new Stack<>(); 23 | 24 | // ❹ 사라진 인형의 총 개수를 저장할 변수를 초기화합니다. 25 | int answer = 0; 26 | 27 | // ❺ moves를 순회하며, 각 열에서 인형을 뽑아 bucket에 추가합니다. 28 | for (int move : moves) { 29 | if (!lanes[move - 1].isEmpty()) { // 해당 열에 인형이 있는 경우 30 | int doll = lanes[move - 1].pop(); 31 | // ❻ 바구니에 인형이 있고, 가장 위에 있는 인형과 같은 경우 32 | if (!bucket.isEmpty() && bucket.peek() == doll) { 33 | bucket.pop(); 34 | answer += 2; 35 | } 36 | else { // ❼ 바구니에 인형이 없거나, 가장 위에 있는 인형과 다른 경우 37 | bucket.push(doll); 38 | } 39 | } 40 | } 41 | 42 | return answer; 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /solution/14.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | import java.util.Stack; 3 | 4 | public class Solution { 5 | 6 | public String solution(int n, int k, String[] cmd) { 7 | // ❶ 삭제된 행의 인덱스를 저장하는 스택 8 | Stack deleted = new Stack<>(); 9 | 10 | // ❷ 각 행을 기준으로 연산에 따른 위치를 표시하기 위한 배열 11 | int[] up = new int[n + 2]; 12 | int[] down = new int[n + 2]; 13 | 14 | for (int i = 0; i < n + 2; i++) { 15 | up[i] = i - 1; 16 | down[i] = i + 1; 17 | } 18 | 19 | // ❸ 현재 위치를 나타내는 인덱스 20 | k++; 21 | 22 | // ❹ 주어진 명령어(cmd) 배열을 하나씩 처리 23 | for (String c : cmd) { 24 | // ❺ 현재 위치를 삭제하고 그 다음 위치로 이동 25 | if (c.startsWith("C")) { 26 | deleted.push(k); 27 | up[down[k]] = up[k]; 28 | down[up[k]] = down[k]; 29 | k = n < down[k] ? up[k] : down[k]; 30 | } 31 | // ❻ 가장 최근에 삭제된 행을 복원 32 | else if (c.startsWith("Z")) { 33 | int restore = deleted.pop(); 34 | down[up[restore]] = restore; 35 | up[down[restore]] = restore; 36 | } 37 | // ❼ U 또는 D를 사용해 현재 위치를 위아래로 이동 38 | else { 39 | String[] s = c.split(" "); 40 | int x = Integer.parseInt(s[1]); 41 | for (int i = 0; i < x; i++) { 42 | k = s[0].equals("U") ? up[k] : down[k]; 43 | } 44 | } 45 | } 46 | 47 | // ❽ 삭제된 행의 위치에 'X'를, 그렇지 않은 행 위치에는 'O'를 저장한 문자열 반환 48 | char[] answer = new char[n]; 49 | Arrays.fill(answer, 'O'); 50 | 51 | for (int i : deleted) { 52 | answer[i - 1] = 'X'; 53 | } 54 | 55 | return new String(answer); 56 | } 57 | 58 | } -------------------------------------------------------------------------------- /solution/15.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayDeque; 2 | 3 | public class Solution { 4 | 5 | public static void main(String[] args) { 6 | System.out.println(solution(5, 2)); 7 | } 8 | 9 | // 이 부분을 변경해서 실행해보세요. 10 | private static int solution(int N, int K) { 11 | // ❶ 1부터 N까지의 번호를 deque에 추가 12 | ArrayDeque deque = new ArrayDeque<>(); 13 | for (int i = 1; i <= N; i++) { 14 | deque.addLast(i); 15 | } 16 | 17 | // ❷ deque에 하나의 요소가 남을 때까지 반복 18 | while (deque.size() > 1) { 19 | // ❸ K번째 요소를 찾기 위해 앞에서부터 제거하고 뒤에 추가 20 | for (int i = 0; i < K - 1; i++) { 21 | deque.addLast(deque.pollFirst()); 22 | } 23 | deque.pollFirst(); // ❹ K번째 요소 제거 24 | } 25 | 26 | return deque.pollFirst(); // ❺ 마지막으로 남은 요소 반환 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /solution/16.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayDeque; 2 | import java.util.Queue; 3 | 4 | public class Solution { 5 | 6 | public int[] solution(int[] progresses, int[] speeds) { 7 | Queue answer = new ArrayDeque<>(); 8 | 9 | int n = progresses.length; 10 | // ❶ 각 작업의 배포 가능일 계산 11 | int[] daysLeft = new int[n]; 12 | for (int i = 0; i < n; i++) { 13 | daysLeft[i] = (int) Math.ceil((100.0 - progresses[i]) / speeds[i]); 14 | } 15 | 16 | int count = 0; // ❷ 배포될 작접의 수 카운트 17 | int maxDay = daysLeft[0]; // ❸ 현재 배포될 작업 중 가장 늦게 배포될 작업의 가능일 18 | 19 | for (int i = 0; i < n; i++) { 20 | if (daysLeft[i] <= maxDay) { // ❹ 배포 가능일이 가장 늦은 배포일보다 빠르면 21 | count++; 22 | } 23 | else { // ❺ 배포 예정일이 기준 배포일보다 느리면 24 | answer.add(count); 25 | count = 1; 26 | maxDay = daysLeft[i]; 27 | } 28 | } 29 | 30 | answer.add(count); // ❻ 마지막으로 카운트된 작업들을 함께 배포 31 | return answer.stream().mapToInt(Integer::intValue).toArray(); 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /solution/17.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayDeque; 2 | import java.util.Arrays; 3 | 4 | public class Solution { 5 | 6 | public String solution(String[] cards1, String[] cards2, String[] goal) { 7 | // cards와 goal을 deque로 변환 8 | ArrayDeque cardsDeque1 = new ArrayDeque<>(Arrays.asList(cards1)); 9 | ArrayDeque cardsDeque2 = new ArrayDeque<>(Arrays.asList(cards2)); 10 | ArrayDeque goalDeque = new ArrayDeque<>(Arrays.asList(goal)); 11 | 12 | // ❶ goalDeque에 문자열이 남아있으면 계속 반복 13 | while (!goalDeque.isEmpty()) { 14 | // ❷ cardsDeque1의 front와 일치하는 경우 15 | if (!cardsDeque1.isEmpty() && cardsDeque1.peekFirst().equals(goalDeque.peekFirst())) { 16 | cardsDeque1.pollFirst(); 17 | goalDeque.pollFirst(); 18 | } 19 | // ❸ cardsDeque2의 front와 일치하는 경우 20 | else if (!cardsDeque2.isEmpty() && cardsDeque2.peekFirst().equals(goalDeque.peekFirst())) { 21 | cardsDeque2.pollFirst(); 22 | goalDeque.pollFirst(); 23 | } 24 | else { 25 | break; // 일치하는 원소를 찾지 못했으므로 종료 26 | } 27 | } 28 | 29 | // ❹ goal이 비었으면 "Yes" 아니면 "No"를 반환 30 | return goalDeque.isEmpty() ? "Yes" : "No"; 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /solution/18.java: -------------------------------------------------------------------------------- 1 | import java.util.HashSet; 2 | 3 | public class Solution { 4 | 5 | public static void main(String[] args) { 6 | System.out.println(solution(new int[]{1, 2, 3, 4, 8}, 6)); 7 | System.out.println(solution(new int[]{2, 3, 5, 9}, 10)); 8 | } 9 | 10 | // 이 부분을 변경해서 실행해보세요. 11 | private static boolean solution(int[] arr, int target) { 12 | HashSet hashSet = new HashSet<>(); 13 | 14 | for (int i : arr) { 15 | // ❶ target에서 현재 원소를 뺀 값이 hashSet에 있는지 확인 16 | if (hashSet.contains(target - i)) { 17 | return true; 18 | } 19 | 20 | // ❷ hashSet에 현재 값 저장 21 | hashSet.add(i); 22 | } 23 | 24 | return false; 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /solution/19.java: -------------------------------------------------------------------------------- 1 | import java.util.HashMap; 2 | 3 | public class Solution { 4 | 5 | public String solution(String[] participant, String[] completion) { 6 | // ❶ 해시맵 생성 7 | HashMap hashMap = new HashMap<>(); 8 | // ❷ 완주한 선수들의 이름을 해시맵에 저장 9 | for (String string : completion) { 10 | hashMap.put(string, hashMap.getOrDefault(string, 0) + 1); 11 | } 12 | 13 | // ❸ 참가한 선수들의 이름을 키로 하는 값을 1씩 감소 14 | for (String string : participant) { 15 | // ❹ 완주하지 못한 선수를 찾으면 반환 16 | if (hashMap.getOrDefault(string, 0) == 0) { 17 | return string; 18 | } 19 | hashMap.put(string, hashMap.get(string) - 1); 20 | } 21 | 22 | return null; 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /solution/20.java: -------------------------------------------------------------------------------- 1 | import java.util.HashMap; 2 | 3 | public class Solution { 4 | 5 | public int solution(String[] want, int[] number, String[] discount) { 6 | // ❶ want, number배열의 값을 해시맵에 저장 7 | HashMap wantMap = new HashMap<>(); 8 | for (int i = 0; i < want.length; i++) { 9 | wantMap.put(want[i], number[i]); 10 | } 11 | 12 | int answer = 0; // ❷ 총 일수를 계산할 변수 초기화 13 | 14 | // ❸ 특정일 i에 회원가입 시 할인받을 수 있는 품목 체크 15 | for (int i = 0; i < discount.length - 9; i++) { 16 | // ❹ i일 회원가입 시 할인받는 제품 및 개수를 담을 해시맵 17 | HashMap discount10d = new HashMap<>(); 18 | 19 | // ❺ i일 회원가입 시 할인받는 제품 및 개수로 해시맵 구성 20 | for (int j = i; j < i + 10; j++) { 21 | if (wantMap.containsKey(discount[j])) { 22 | discount10d.put(discount[j], discount10d.getOrDefault(discount[j], 0) + 1); 23 | } 24 | } 25 | 26 | // ❻ 할인하는 상품의 개수가 원하는 수량과 일치하면 정답 변수에 1 추가 27 | if (discount10d.equals(wantMap)) 28 | answer++; 29 | } 30 | 31 | 32 | return answer; 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /solution/21.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.HashMap; 3 | 4 | public class Solution { 5 | 6 | private String[] solution(String[] record) { 7 | // Enter/Leave 메세지를 저장할 해시맵 생성 8 | HashMap msg = new HashMap<>(); 9 | msg.put("Enter", "님이 들어왔습니다."); 10 | msg.put("Leave", "님이 나갔습니다."); 11 | 12 | HashMap uid = new HashMap<>(); 13 | 14 | // ❶ record의 각 줄을 하나씩 처리 15 | for (String s : record) { 16 | String[] cmd = s.split(" "); 17 | if (cmd.length == 3) { // ❷ Enter 또는 Change인 경우 18 | uid.put(cmd[1], cmd[2]); 19 | } 20 | } 21 | 22 | // 답을 저장할 answer List 생성 23 | ArrayList answer = new ArrayList<>(); 24 | 25 | // ❸ record의 각 줄을 하나씩 처리 26 | for (String s : record) { 27 | String[] cmd = s.split(" "); 28 | // ❹ 각 상태에 맞는 메세지를 answer에 저장 29 | if (msg.containsKey(cmd[0])) { 30 | answer.add(uid.get(cmd[1]) + msg.get(cmd[0])); 31 | } 32 | } 33 | 34 | return answer.toArray(new String[0]); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /solution/22.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.HashMap; 3 | import java.util.Map; 4 | import java.util.stream.Stream; 5 | 6 | public class Solution { 7 | 8 | public int[] solution(String[] genres, int[] plays) { 9 | HashMap> genreMap = new HashMap<>(); 10 | HashMap playMap = new HashMap<>(); 11 | 12 | // ❶ 장르별 총 재생 횟수와 각 곡의 재생 횟수 저장 13 | for (int i = 0; i < genres.length; i++) { 14 | String genre = genres[i]; 15 | int play = plays[i]; 16 | if (!genreMap.containsKey(genre)) { 17 | genreMap.put(genre, new ArrayList<>()); 18 | playMap.put(genre, 0); 19 | } 20 | genreMap.get(genre).add(new int[]{i, play}); 21 | playMap.put(genre, playMap.get(genre) + play); 22 | } 23 | 24 | ArrayList answer = new ArrayList<>(); 25 | 26 | // ❷ 총 재생 횟수가 많은 장르순으로 내림차순 정렬 27 | Stream> sortedGenre = playMap.entrySet() 28 | .stream() 29 | .sorted((o1, o2) -> Integer.compare(o2.getValue(), o1.getValue())); 30 | 31 | // ❸ 각 장르 내에서 노래를 재생 횟수 순으로 정렬해 최대 2곡까지 선택 32 | sortedGenre.forEach(entry -> { 33 | Stream sortedSongs = genreMap.get(entry.getKey()).stream() 34 | .sorted((o1, o2) -> Integer.compare(o2[1], o1[1])) 35 | .limit(2); 36 | sortedSongs.forEach(song -> answer.add(song[0])); 37 | }); 38 | 39 | return answer.stream().mapToInt(Integer::intValue).toArray(); 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /solution/23.java: -------------------------------------------------------------------------------- 1 | import java.util.HashMap; 2 | import java.util.HashSet; 3 | import java.util.Map; 4 | 5 | public class Solution { 6 | 7 | public int[] solution(String[] id_list, String[] report, int k) { 8 | // 신고당한 유저 - 신고 유저 집합을 저장할 해시맵 9 | HashMap> reportedUser = new HashMap<>(); 10 | // 처리 결과 메일을 받은 유저 - 받은 횟수를 저장할 해시맵 11 | HashMap count = new HashMap<>(); 12 | 13 | // ❶ 신고 기록 순회 14 | for (String r : report) { 15 | String[] s = r.split(" "); 16 | String userId = s[0]; 17 | String reportedId = s[1]; 18 | 19 | if (!reportedUser.containsKey(reportedId)) { // ❷ 신고당한 기록이 없다면 20 | reportedUser.put(reportedId, new HashSet<>()); 21 | } 22 | // ❸ 신고한 사람의 아이디를 해시맵의 value인 해시셋에 추가 23 | reportedUser.get(reportedId).add(userId); 24 | } 25 | 26 | for (Map.Entry> entry : reportedUser.entrySet()) { 27 | if (entry.getValue().size() >= k) { // ❹ 정지 기준에 만족하는지 확인 28 | for (String uid : entry.getValue()) { // ❺ 해시셋을 순회하며 count 계산 29 | count.put(uid, count.getOrDefault(uid, 0) + 1); 30 | } 31 | } 32 | } 33 | 34 | int[] answer = new int[id_list.length]; 35 | 36 | // ❻ 각 아이디별 메일을 받은 횟수를 순서대로 정리 37 | for (int i = 0; i < id_list.length; i++) { 38 | answer[i] = count.getOrDefault(id_list[i], 0); 39 | } 40 | 41 | return answer; 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /solution/24.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | public class Solution { 4 | 5 | // 만들 수 있는 메뉴 구성과 총 주문 수를 저장할 해시맵 6 | private static HashMap> courseMap; 7 | 8 | public String[] solution(String[] orders, int[] course) { 9 | // 해시맵 초기화 10 | courseMap = new HashMap<>(); 11 | for (int i : course) { 12 | courseMap.put(i, new HashMap<>()); 13 | } 14 | 15 | // ❶ 코스를 배열로 만들고 오름차순 정렬해서 가능한 모든 메뉴 구성을 구함 16 | for (String order : orders) { 17 | char[] orderArray = order.toCharArray(); 18 | Arrays.sort(orderArray); 19 | combinations(0, orderArray, ""); 20 | } 21 | 22 | ArrayList answer = new ArrayList<>(); 23 | 24 | // ❷ 모든 코스 후보에 대해서 25 | for (HashMap count : courseMap.values()) { 26 | count.values() 27 | .stream() 28 | .max(Comparator.comparingInt(o -> o)) // ❸ 가장 빈도수가 높은 코스를 찾음 29 | .ifPresent(cnt -> count.entrySet() // ❹ 코스에 대한 메뉴 수가 가능할 때만 30 | .stream() 31 | // ❺ 최소 2명 이상의 손님으로부터 주문된 단품메뉴 조합에 대해서만 32 | .filter(entry -> cnt.equals(entry.getValue()) && cnt > 1) 33 | // ❻ 코스 메뉴만 answer 리스트에 추가 34 | .forEach(entry -> answer.add(entry.getKey()))); 35 | } 36 | 37 | Collections.sort(answer); // ❼ 오름차순으로 정렬 38 | return answer.toArray(new String[0]); 39 | } 40 | 41 | // 만들 수 있는 모든 조합을 재귀 함수를 이용해서 구현 42 | public static void combinations(int idx, char[] order, String result) { 43 | // 필요한 코스 메뉴의 수와 일치하는 것만 저장 44 | if (courseMap.containsKey(result.length())) { 45 | HashMap map = courseMap.get(result.length()); 46 | // 해당 코스의 수를 1증가 47 | map.put(result, map.getOrDefault(result, 0) + 1); 48 | } 49 | 50 | for (int i = idx; i < order.length; i++) { 51 | combinations(i + 1, order, result + order[i]); 52 | } 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /solution/25.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | public class Solution { 4 | 5 | public static void main(String[] args) { 6 | int[] input = {1, 2, 3, 4, 5, 6, 7}; 7 | System.out.println(Arrays.toString(solution(input))); 8 | } 9 | 10 | // 이 부분을 변경해서 실행해보세요. 11 | public static String[] solution(int[] nodes) { 12 | String[] result = new String[3]; 13 | result[0] = preorder(nodes, 0).trim(); // 마지막 공백 제거 14 | result[1] = inorder(nodes, 0).trim(); // 마지막 공백 제거 15 | result[2] = postorder(nodes, 0).trim(); // 마지막 공백 제거 16 | return result; 17 | } 18 | 19 | private static String preorder(int[] nodes, int idx) { 20 | if (idx >= nodes.length) { // idx가 범위를 벗어나면 빈 문자열 반환 21 | return ""; 22 | } 23 | 24 | // 루트 노드 -> 왼쪽 서브 트리 -> 오른쪽 서브 트리 순으로 재귀 호출하여 결과를 이어붙임 25 | return nodes[idx] + " " + 26 | preorder(nodes, 2 * idx + 1) + 27 | preorder(nodes, 2 * idx + 2); 28 | } 29 | 30 | private static String inorder(int[] nodes, int idx) { 31 | if (idx >= nodes.length) { // idx가 범위를 벗어나면 빈 문자열 반환 32 | return ""; 33 | } 34 | 35 | // 왼쪽 서브 트리 -> 루트 노드 -> 오른쪽 서브 트리 순으로 재귀 호출하여 결과를 이어붙임 36 | return inorder(nodes, 2 * idx + 1) + 37 | nodes[idx] + " " + 38 | inorder(nodes, 2 * idx + 2); 39 | } 40 | 41 | private static String postorder(int[] nodes, int idx) { 42 | if (idx >= nodes.length) { // idx가 범위를 벗어나면 빈 문자열 반환 43 | return ""; 44 | } 45 | 46 | // 왼쪽 서브 트리 -> 오른쪽 서브 트리 -> 루트 노드 순으로 재귀 호출하여 결과를 이어붙임 47 | return postorder(nodes, 2 * idx + 1) + 48 | postorder(nodes, 2 * idx + 2) + 49 | nodes[idx] + " "; 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /solution/26.java: -------------------------------------------------------------------------------- 1 | public class Solution { 2 | 3 | public int solution(int n, int a, int b) { 4 | int answer; 5 | 6 | for(answer = 0; a != b; answer++) { 7 | a = (a + 1) / 2; 8 | b = (b + 1) / 2; 9 | } 10 | 11 | return answer; 12 | } 13 | 14 | } -------------------------------------------------------------------------------- /solution/27.java: -------------------------------------------------------------------------------- 1 | import java.util.HashMap; 2 | 3 | public class Solution { 4 | 5 | public int[] solution(String[] enroll, String[] referral, String[] seller, int[] amount) { 6 | // ❶ parent 해시맵. key는 enroll의 노드, value는 referral의 노드로 구성됨 7 | HashMap parent = new HashMap<>(); 8 | for (int i = 0; i < enroll.length; i++) { 9 | parent.put(enroll[i], referral[i]); 10 | } 11 | 12 | // ❷ total 해시맵 생성 13 | HashMap total = new HashMap<>(); 14 | 15 | // ❸ seller 배열과 amount 배열을 이용하여 이익 분배 16 | for (int i = 0; i < seller.length; i++) { 17 | String curName = seller[i]; 18 | // ❹ 판매자가 판매한 총 금액 계산 19 | int money = amount[i] * 100; 20 | // ❺ 판매자부터 차례대로 상위 노드로 이동하며 이익 분배 21 | while (money > 0 && !curName.equals("-")) { 22 | // ❻ 현재 판매자가 받을 금액 계산(10%를 제외한 금액) 23 | total.put(curName, total.getOrDefault(curName, 0) + money - (money / 10)); 24 | curName = parent.get(curName); 25 | // ❼ 10% 를 제외한 금액 계산 26 | money /= 10; 27 | } 28 | } 29 | 30 | // ❽ enroll 배열의 모든 노드에 대해 해당하는 이익을 배열로 반환 31 | int[] answer = new int[enroll.length]; 32 | for (int i = 0; i < enroll.length; i++) { 33 | answer[i] = total.getOrDefault(enroll[i], 0); 34 | } 35 | return answer; 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /solution/28.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayDeque; 2 | import java.util.ArrayList; 3 | import java.util.HashSet; 4 | 5 | public class Solution { 6 | 7 | // 현재 위치, 양의 수, 늑대의 수 방문한 노드 저장을 위한 클래스 8 | private static class Info { 9 | int node, sheep, wolf; 10 | HashSet visited; 11 | 12 | public Info(int node, int sheep, int wolf, HashSet visited) { 13 | this.node = node; 14 | this.sheep = sheep; 15 | this.wolf = wolf; 16 | this.visited = visited; 17 | } 18 | } 19 | 20 | private static ArrayList[] tree; // 트리 정보를 저장할 인접리스트 21 | 22 | // ❶ 트리 구축 메소드 23 | private static void buildTree(int[] info, int[][] edges) { 24 | tree = new ArrayList[info.length]; 25 | for (int i = 0; i < tree.length; i++) { 26 | tree[i] = new ArrayList<>(); 27 | } 28 | 29 | for (int[] edge : edges) { 30 | tree[edge[0]].add(edge[1]); 31 | } 32 | } 33 | 34 | public int solution(int[] info, int[][] edges) { 35 | buildTree(info, edges); // ❷ 트리 생성 36 | 37 | int answer = 0; // ❸ 최대 양의 수를 저장할 변수 38 | 39 | // ❹ BFS를 위한 큐 생성 및 초기 상태 설정 40 | ArrayDeque queue = new ArrayDeque<>(); 41 | queue.add(new Info(0, 1, 0, new HashSet<>())); 42 | 43 | // BFS(너비 우선 탐색) 시작 44 | while (!queue.isEmpty()) { 45 | // ❺ 큐에서 현재 상태를 꺼냄 46 | Info now = queue.poll(); 47 | // ❻ 최대 양의 수 업데이트 48 | answer = Math.max(answer, now.sheep); 49 | // ❼ 방문한 노드 집합에 현재 노드의 이웃 노드 추가 50 | now.visited.addAll(tree[now.node]); 51 | 52 | // ❽ 인접한 노드들에 대해 탐색 53 | for (int next : now.visited) { 54 | // ❾ 기존 해시셋의 데이터를 복사하고 현재 방문한 정점을 해시셋에서 제거 55 | HashSet set = new HashSet<>(now.visited); 56 | set.remove(next); 57 | 58 | if (info[next] == 1) { // ➓ 늑대일 경우 59 | if (now.sheep != now.wolf + 1) { 60 | queue.add(new Info(next, now.sheep, now.wolf + 1, set)); 61 | } 62 | } 63 | else { // ⓫ 양일 경우 64 | queue.add(new Info(next, now.sheep + 1, now.wolf, set)); 65 | } 66 | } 67 | } 68 | 69 | return answer; 70 | } 71 | 72 | } -------------------------------------------------------------------------------- /solution/29.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.Arrays; 3 | 4 | public class Code324A_길찾기게임 { 5 | 6 | // ❶ Node 클래스 정의 7 | private static class Node { 8 | int x, y, num; // 노드의 좌표, 번호 저장 9 | Node left, right; // 노드의 왼쪽, 오른쪽 자식 노드 10 | 11 | public Node(int num, int x, int y) { 12 | this.num = num; 13 | this.x = x; 14 | this.y = y; 15 | } 16 | } 17 | 18 | // ❷ 이진 트리 생성 메소드 19 | private static Node makeBT(int[][] nodeinfo) { 20 | // ❸ 각 노드에 대한 좌표, 번호를 배열에 저장 21 | Node[] nodes = new Node[nodeinfo.length]; 22 | for (int i = 0; i < nodeinfo.length; i++) { 23 | nodes[i] = new Node(i + 1, nodeinfo[i][0], nodeinfo[i][1]); 24 | } 25 | 26 | // ❹ y 기준으로 내림차순 정렬, y가 같다면 x를 기준으로 오름차순 정렬 27 | Arrays.sort(nodes, (o1, o2) -> { 28 | if (o1.y == o2.y) 29 | return Integer.compare(o1.x, o2.x); 30 | return Integer.compare(o2.y, o1.y); 31 | }); 32 | 33 | Node root = nodes[0]; // 맨 처음 노드는 무조건 루트 34 | 35 | for (int i = 1; i < nodes.length; i++) { 36 | Node parent = root; 37 | while (true) { 38 | // ❺ 부모 노드의 x좌표가 더 크면 왼쪽으로 39 | if (nodes[i].x < parent.x) { 40 | if (parent.left == null) { 41 | parent.left = nodes[i]; 42 | break; 43 | } 44 | else { 45 | parent = parent.left; 46 | } 47 | } 48 | // ❻ 부모 노드의 x좌표가 더 작거나 같으면 오른쪽으로 49 | else { 50 | if (parent.right == null) { 51 | parent.right = nodes[i]; 52 | break; 53 | } 54 | else { 55 | parent = parent.right; 56 | } 57 | } 58 | } 59 | } 60 | 61 | return nodes[0]; 62 | } 63 | 64 | // ❼ 전위 순회 메소드 65 | private static void preOrder(Node curr, ArrayList answer) { 66 | if (curr == null) { 67 | return; 68 | } 69 | answer.add(curr.num); 70 | preOrder(curr.left, answer); 71 | preOrder(curr.right, answer); 72 | } 73 | 74 | // ❽ 후위 순회 메소드 75 | private static void postOrder(Node curr, ArrayList answer) { 76 | if (curr == null) { 77 | return; 78 | } 79 | postOrder(curr.left, answer); 80 | postOrder(curr.right, answer); 81 | answer.add(curr.num); 82 | } 83 | 84 | public int[][] solution(int[][] nodeinfo) { 85 | Node root = makeBT(nodeinfo); // 이진트리 생성 86 | 87 | ArrayList preOrderList = new ArrayList<>(); 88 | preOrder(root, preOrderList); // 전위 순회 89 | ArrayList postOrderList = new ArrayList<>(); 90 | postOrder(root, postOrderList); // 후위 순회 91 | 92 | // 결과 반환 93 | int[][] answer = new int[2][nodeinfo.length]; 94 | answer[0] = preOrderList.stream().mapToInt(Integer::intValue).toArray(); 95 | answer[1] = postOrderList.stream().mapToInt(Integer::intValue).toArray(); 96 | 97 | return answer; 98 | } 99 | 100 | } -------------------------------------------------------------------------------- /solution/30.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.Arrays; 3 | 4 | public class Solution { 5 | 6 | public static void main(String[] args) { 7 | int[][] operations1 = {{0, 0, 1}, {0, 1, 2}, {1, 1, 2}}; 8 | System.out.println(Arrays.toString(solution(3, operations1))); 9 | int[][] operations2 = {{0, 0, 1}, {1, 1, 2}, {0, 1, 2}, {1, 0, 2}}; 10 | System.out.println(Arrays.toString(solution(3, operations2))); 11 | } 12 | 13 | // 부모 저장을 위한 배열 14 | private static int[] parent; 15 | 16 | // 루트 노드를 찾는 메소드 17 | private static int find(int x) { 18 | // 만약 x의 부모가 자기 자신이면, 즉 x가 루트 노드라면 x를 반환 19 | if (parent[x] == x) 20 | return x; 21 | // 그렇지 않다면 x의 부모를 찾아서 parent[x]에 저장합니다. 22 | parent[x] = find(parent[x]); 23 | return parent[x]; // 찾은 루트 노드를 반환 24 | } 25 | 26 | private static void union(int x, int y) { 27 | int root1 = find(x); // x가 속한 집합의 루트 노드 찾기 28 | int root2 = find(y); // y가 속한 집합의 루트 노드 찾기 29 | 30 | parent[root2] = root1; // y가 속한 집합을 x가 속한 집합에 합침 31 | } 32 | 33 | // 이 부분을 변경해서 실행해보세요. 34 | private static Boolean[] solution(int k, int[][] operation) { 35 | // 노드의 수 만큼 배열 생성 36 | parent = new int[k]; 37 | // 처음에는 각 노드가 자기 자신을 부모로 가지도록 초기화 38 | for (int i = 0; i < k; i++) { 39 | parent[i] = i; 40 | } 41 | 42 | ArrayList answer = new ArrayList<>(); 43 | 44 | for (int[] op : operation) { 45 | if (op[0] == 0) { // 0 연산이면 46 | union(op[1], op[2]); 47 | } 48 | else { // 1 연산이면 49 | answer.add(find(op[1]) == find(op[2])); 50 | } 51 | } 52 | 53 | return answer.toArray(new Boolean[0]); 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /solution/31.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | import java.util.HashSet; 3 | import java.util.stream.Collectors; 4 | 5 | public class Solution { 6 | 7 | public int solution(int[] nums) { 8 | // ❶ nums 리스트에서 중복을 제거한 집합(set)을 구함 9 | HashSet set = Arrays.stream(nums).boxed().collect(Collectors.toCollection(HashSet::new)); 10 | // ❷ 폰켓몬의 총 수 11 | int n = nums.length; 12 | // ❸ 선택할 폰켓몬의 수 13 | int k = n / 2; 14 | // ❹ 중복을 제거한 폰켓몬의 종류 수와 선택할 폰켓몬의 수 중 작은 값 반환 15 | return Math.min(k, set.size()); 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /solution/32.java: -------------------------------------------------------------------------------- 1 | import java.util.HashSet; 2 | 3 | public class Solution { 4 | 5 | public int[] solution(int n, String[] words) { 6 | // ❶ 이미 사용한 단어를 저장하는 set 7 | HashSet usedWords = new HashSet<>(); 8 | // ❷ 이전 단어의 마지막 글자 9 | char prevWord = words[0].charAt(0); 10 | 11 | for (int i = 0; i < words.length; i++) { 12 | // ❸ 이미 사용한 단어이거나 첫 글자가 이전 단어와 일치하지 않으면 13 | if (usedWords.contains(words[i]) || words[i].charAt(0) != prevWord) { 14 | // ❹ 탈락하는 사람의 번호와 차례를 반환 15 | return new int[]{(i % n) + 1, (i / n) + 1}; 16 | } 17 | // ❺ 사용한 단어로 추가 18 | usedWords.add(words[i]); 19 | // ❻ 이전 단어의 마지막 글자 업데이트 20 | prevWord = words[i].charAt(words[i].length() - 1); 21 | } 22 | 23 | // ❼ 모두 통과했을 경우 반환값 24 | return new int[]{0, 0}; 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /solution/33.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | public class Solution { 4 | 5 | private static int[] parent; 6 | 7 | private static int find(int x) { 8 | // ❶ x가 속한 집합의 루트 노드 찾기 9 | if (parent[x] == x) 10 | return x; 11 | // ❷ 경로 압축: x의 부모를 루트로 설정 12 | return parent[x] = find(parent[x]); 13 | } 14 | 15 | private static void union(int x, int y) { 16 | // ❸ 두 집합을 하나의 집합으로 합치기 17 | int root1 = find(x); 18 | int root2 = find(y); 19 | parent[root2] = root1; 20 | } 21 | 22 | public int solution(int n, int[][] costs) { 23 | // ❹ 비용을 기준으로 다리를 오름차순 정렬 24 | Arrays.sort(costs, (o1, o2) -> Integer.compare(o1[2], o2[2])); 25 | 26 | // ❺ parent 배열 초기화 27 | parent = new int[n]; 28 | for (int i = 0; i < n; i++) { 29 | parent[i] = i; 30 | } 31 | 32 | int answer = 0; // 최소 신장 트리의 총 비용 33 | int edges = 0; // 연결된 다리의 수 34 | 35 | for (int[] edge : costs) { 36 | // ❻ n - 1개의 다리가 연결된 경우 모든 섬이 연결됨 37 | if (edges == n - 1) 38 | break; 39 | 40 | // ❼ 현재 다리가 연결하는 두 섬이 이미 연결되어 있는지 확인 41 | if (find(edge[0]) != find(edge[1])) { 42 | // ❽ 두 섬을 하나의 집합으로 연결함 43 | union(edge[0], edge[1]); 44 | // ❾ 현재 다리의 건설 비용을 비용에 추가 45 | answer += edge[2]; 46 | // ➓ 사용된 다리의 수 1증가 47 | edges++; 48 | } 49 | } 50 | 51 | return answer; 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /solution/34.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.Arrays; 3 | 4 | public class Solution { 5 | 6 | public static void main(String[] args) { 7 | int[][] graph1 = {{1, 2}, {2, 3}, {3, 4}, {4, 5}}; 8 | System.out.println(Arrays.toString(solution(graph1, 1, 5))); 9 | int[][] graph2 = {{1, 2}, {1, 3}, {2, 4}, {2, 5}, {3, 6}, {5, 6}}; 10 | System.out.println(Arrays.toString(solution(graph2, 1, 6))); 11 | } 12 | 13 | // 인접 리스트 저장할 ArrayList 배열 14 | private static ArrayList[] adjList; 15 | 16 | // 방문 여부를 저장할 boolean 배열 17 | private static boolean[] visited; 18 | 19 | private static ArrayList answer; 20 | 21 | // 이 부분을 변경해서 실행해보세요. 22 | private static int[] solution(int[][] graph, int start, int n) { 23 | // ❶ 인접 리스트 초기화 24 | adjList = new ArrayList[n + 1]; 25 | for (int i = 0; i < adjList.length; i++) { 26 | adjList[i] = new ArrayList<>(); 27 | } 28 | 29 | // ❷ 그래프를 인접 리스트로 변환 30 | for (int[] edge : graph) { 31 | adjList[edge[0]].add(edge[1]); 32 | } 33 | 34 | // DFS를 순회한 결과를 반환 35 | visited = new boolean[n + 1]; 36 | answer = new ArrayList<>(); 37 | dfs(start); // ❼ 시작 노드에서 깊이 우선 탐색 시작 38 | 39 | // ❽ DFS 탐색 결과 반환 40 | return answer.stream().mapToInt(Integer::intValue).toArray(); 41 | } 42 | 43 | // ❸ DFS 탐색 메소드 44 | private static void dfs(int now) { 45 | visited[now] = true; // ❹ 현재 노드를 방문했음을 저장 46 | answer.add(now); // ❺ 현재 노드를 결과 리스트에 추가 47 | // ❻ 현재 노드와 인접한 노드 순회 48 | for (int next : adjList[now]) { 49 | if (!visited[next]) { 50 | dfs(next); 51 | } 52 | } 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /solution/35.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayDeque; 2 | import java.util.ArrayList; 3 | import java.util.Arrays; 4 | 5 | public class Solution { 6 | 7 | public static void main(String[] args) { 8 | int[][] graph1 = {{1, 2}, {1, 3}, {2, 4}, {2, 5}, {3, 6}, {3, 7}, {4, 8}, {5, 8}, {6, 9}, {7, 9}}; 9 | System.out.println(Arrays.toString(solution(graph1, 1, 9))); 10 | int[][] graph2 = {{1, 3}, {3, 4}, {3, 5}, {5, 2}}; 11 | System.out.println(Arrays.toString(solution(graph2, 1, 5))); 12 | } 13 | 14 | // 인접 리스트 저장할 ArrayList 배열 15 | private static ArrayList[] adjList; 16 | 17 | // 방문 여부를 저장할 boolean 배열 18 | private static boolean[] visited; 19 | 20 | private static ArrayList answer; 21 | 22 | // 이 부분을 변경해서 실행해보세요. 23 | private static int[] solution(int[][] graph, int start, int n) { 24 | adjList = new ArrayList[n + 1]; 25 | for (int i = 0; i < adjList.length; i++) { 26 | adjList[i] = new ArrayList<>(); 27 | } 28 | 29 | for (int[] edge : graph) { 30 | adjList[edge[0]].add(edge[1]); 31 | } 32 | 33 | // ❶ 방문 여부를 저장할 배열 34 | visited = new boolean[n + 1]; 35 | answer = new ArrayList<>(); 36 | bfs(start); // ❽ 시작 노드에서 너비 우선 탐색 시작 37 | 38 | return answer.stream().mapToInt(Integer::intValue).toArray(); 39 | } 40 | 41 | // BFS 탐색 메소드 42 | private static void bfs(int start) { 43 | // ❷ 탐색시 맨 처음 방문할 노드를 add 하고 방문처리 44 | ArrayDeque queue = new ArrayDeque<>(); 45 | queue.add(start); 46 | visited[start] = true; 47 | 48 | // ❸ 큐가 비어 있지 않은 동안 반복 49 | while (!queue.isEmpty()) { 50 | // ❹ 큐에 있는 원소 중 가장 먼저 추가된 원소를 poll하고 정답 리스트에 추가 51 | int now = queue.poll(); 52 | answer.add(now); 53 | // ❺ 인접한 이웃 노드들에 대해서 54 | for (int next : adjList[now]) { 55 | if (!visited[next]) { // ❻ 방문하지 않은 인접한 노드인 경우 56 | // ❼ 인접한 노드를 방문 처리함 57 | queue.add(next); 58 | visited[next] = true; 59 | } 60 | } 61 | } 62 | } 63 | 64 | } -------------------------------------------------------------------------------- /solution/36.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.Arrays; 3 | import java.util.PriorityQueue; 4 | 5 | public class Solution { 6 | 7 | public static void main(String[] args) { 8 | int[][] graph = {{0, 1, 9}, {0, 2, 3}, {1, 0, 5}, {2, 1, 1}}; 9 | System.out.println(Arrays.toString(solution(graph, 0, 3))); 10 | int[][] graph2 = {{0, 1, 1}, {1, 2, 5}, {2, 3, 1}}; 11 | System.out.println(Arrays.toString(solution(graph2, 0, 4))); 12 | } 13 | 14 | // 노드의 정보(노드 번호와 거리)를 쌍으로 저장할 클래스 생성 15 | private static class Node { 16 | int dest, cost; 17 | 18 | public Node(int dest, int cost) { 19 | this.dest = dest; 20 | this.cost = cost; 21 | } 22 | } 23 | 24 | // 이 부분을 변경해서 실행해보세요. 25 | public static int[] solution(int[][] graph, int start, int n) { 26 | // ❶ 인접 리스트를 저장할 ArrayList 배열 초기화 27 | ArrayList[] adjList = new ArrayList[n]; 28 | for (int i = 0; i < n; i++) { 29 | adjList[i] = new ArrayList<>(); 30 | } 31 | 32 | // ❷ graph 정보를 인접 리스트로 저장 33 | for (int[] edge : graph) { 34 | adjList[edge[0]].add(new Node(edge[1], edge[2])); 35 | } 36 | 37 | int[] dist = new int[n]; 38 | // ❸ 모든 노드의 거리 값을 무한대로 초기화 39 | Arrays.fill(dist, Integer.MAX_VALUE); 40 | 41 | // ❹ 시작 노드의 거리 값은 0으로 초기화 42 | dist[start] = 0; 43 | 44 | // ❺ 우선순위 큐를 생성하고 시작 노드를 삽입 45 | PriorityQueue pq = new PriorityQueue<>((o1, o2) -> Integer.compare(o1.cost, o2.cost)); 46 | pq.add(new Node(start, 0)); 47 | 48 | while (!pq.isEmpty()) { 49 | // ❻ 현재 가장 거리가 짧은 노드를 가져옴 50 | Node now = pq.poll(); 51 | 52 | // ❼ 만약 현재 노드의 거리 값이 큐에서 가져온 거리 값보다 크면, 해당 노드는 이미 방문한 것이므로 무시 53 | if (dist[now.dest] < now.cost) 54 | continue; 55 | 56 | // ❽ 현재 노드와 인접한 노드들의 거리 값을 계산하여 업데이트 57 | for (Node next : adjList[now.dest]) { 58 | // ❾ 기존에 발견했던 거리보다 더 짧은 거리를 발견하면 거리 값을 갱신하고 큐에 넣음 59 | if (dist[next.dest] > now.cost + next.cost) { 60 | dist[next.dest] = now.cost + next.cost; 61 | pq.add(new Node(next.dest, dist[next.dest])); 62 | } 63 | } 64 | } 65 | 66 | // ➓ 최단 거리를 담고 있는 배열을 반환 67 | return dist; 68 | } 69 | 70 | } -------------------------------------------------------------------------------- /solution/37.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayDeque; 2 | 3 | public class Solution { 4 | 5 | // ❶ 이동할 수 있는 방향을 나타내는 배열 rx, ry 선언 6 | private static final int[] rx = {0, 0, 1, -1}; 7 | private static final int[] ry = {1, -1, 0, 0}; 8 | 9 | private static class Node { 10 | int r, c; 11 | 12 | public Node(int r, int c) { 13 | this.r = r; 14 | this.c = c; 15 | } 16 | } 17 | 18 | public int solution(int[][] maps) { 19 | // ❷ 맵의 크기를 저장하는 변수 선언 20 | int N = maps.length; 21 | int M = maps[0].length; 22 | 23 | // ❸ 최단 거리를 저장할 배열 생성 24 | int[][] dist = new int[N][M]; 25 | 26 | // ❹ bfs 탐색을 위한 큐 생성 27 | ArrayDeque queue = new ArrayDeque<>(); 28 | 29 | // ❺ 시작 정점에 대해서 큐에 추가, 최단 거리 저장 30 | queue.addLast(new Node(0, 0)); 31 | dist[0][0] = 1; 32 | 33 | // ❻ queue가 빌 때까지 반복 34 | while (!queue.isEmpty()) { 35 | Node now = queue.pollFirst(); 36 | 37 | // ❼ 현재 위치에서 이동할 수 있는 모든 방향 38 | for (int i = 0; i < 4; i++) { 39 | int nr = now.r + rx[i]; 40 | int nc = now.c + ry[i]; 41 | 42 | // ❽ 맵 밖으로 나가는 경우 예외처리 43 | if (nr < 0 || nc < 0 || nr >= N || nc >= M) 44 | continue; 45 | 46 | // ❾ 벽으로 가는 경우 예외처리 47 | if (maps[nr][nc] == 0) 48 | continue; 49 | 50 | // ➓ 이동한 위치가 처음 방문하는 경우, queue에 추가하고 거리 갱신 51 | if (dist[nr][nc] == 0) { 52 | queue.addLast(new Node(nr, nc)); 53 | dist[nr][nc] = dist[now.r][now.c] + 1; 54 | } 55 | } 56 | } 57 | 58 | // 목적지까지 최단 거리 반환, 목적지에 도달하지 못한 경우에는 -1 반환 59 | return dist[N - 1][M - 1] == 0 ? -1 : dist[N - 1][M - 1]; 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /solution/38.java: -------------------------------------------------------------------------------- 1 | public class Solution { 2 | 3 | private static boolean[] visit; 4 | private static int[][] computer; 5 | 6 | private static void dfs(int now) { 7 | visit[now] = true; // ❶ 현재 노드 방문 처리 8 | for (int i = 0; i < computer[now].length; i++) { 9 | // ❷ 연결되어 있으며 방문하지 않은 노드라면 10 | if (computer[now][i] == 1 && !visit[i]) { 11 | dfs(i); // ❸ 해당 노드를 방문하러 이동 12 | } 13 | } 14 | } 15 | 16 | public int solution(int n, int[][] computers) { 17 | int answer = 0; 18 | computer = computers; 19 | visit = new boolean[n]; // ❹ 방문 여부를 저장할 배열 20 | 21 | for (int i = 0; i < n; i++) { 22 | if (!visit[i]) { // ❺ 아직 방문하지 않은 노드라면 해당 노드를 시작으로 깊이 우선 탐색 진행 23 | dfs(i); 24 | answer++; // ❻ DFS로 연결된 노드들을 모두 방문하면서 네트워크 개수 증가 25 | } 26 | } 27 | 28 | return answer; 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /solution/39.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayDeque; 2 | 3 | public class Solution { 4 | 5 | // ❶ 위, 아래, 왼쪽, 오른쪽 이동 방향 6 | private static final int[] dx = {0, 0, -1, 1}; 7 | private static final int[] dy = {-1, 1, 0, 0}; 8 | 9 | // ❷ 위치 정보(x, y)를 저장할 클래스 생성 10 | private static class Point { 11 | int nx, ny; 12 | 13 | public Point(int nx, int ny) { 14 | this.nx = nx; 15 | this.ny = ny; 16 | } 17 | } 18 | 19 | private static char[][] map; 20 | private static int N, M; 21 | 22 | public int solution(String[] maps) { 23 | N = maps.length; 24 | M = maps[0].length(); 25 | 26 | // ❸ 미로에 대한 정보를 배열로 저장 27 | map = new char[N][M]; 28 | for (int i = 0; i < N; i++) { 29 | map[i] = maps[i].toCharArray(); 30 | } 31 | 32 | Point start = null, end = null, lever = null; 33 | 34 | // ❹ 시작 지점, 출구 그리고 레버의 위치를 찾음 35 | for (int i = 0; i < N; i++) { 36 | for (int j = 0; j < M; j++) { 37 | if (map[i][j] == 'S') start = new Point(j, i); 38 | else if (map[i][j] == 'E') end = new Point(j, i); 39 | else if (map[i][j] == 'L') lever = new Point(j, i); 40 | } 41 | } 42 | 43 | // ❺ 시작 자점 -> 레버, 레버 -> 출구까지의 최단 거리를 각각 구함 44 | int startLever = bfs(start, lever); 45 | int leverEnd = bfs(lever, end); 46 | 47 | // ❻ 도착 불가능한 경우는 -1, 도착 가능한 경우는 최단 거리를 반환 48 | if (startLever == -1 || leverEnd == -1) 49 | return -1; 50 | else 51 | return startLever + leverEnd; 52 | } 53 | 54 | // start -> end 로 너비 우선 탐색하여 최단거리 반환 55 | private static int bfs(Point start, Point end) { 56 | // ❼ 너비 우선 탐색 초기 과정 57 | int[][] dist = new int[N][M]; 58 | ArrayDeque queue = new ArrayDeque<>(); 59 | 60 | dist[start.ny][start.nx] = 1; 61 | queue.add(start); 62 | 63 | while (!queue.isEmpty()) { 64 | Point now = queue.poll(); 65 | 66 | // ❽ 네 방향으로 이동 67 | for (int i = 0; i < 4; i++) { 68 | int nextX = now.nx + dx[i]; 69 | int nextY = now.ny + dy[i]; 70 | 71 | // ❾ 범위를 벗어나는 경우 예외 처리 72 | if (nextX < 0 || nextX >= M || nextY < 0 || nextY >= N) 73 | continue; 74 | 75 | // ➓ 이미 방문한 지점인 경우 탐색하지 않음 76 | if (dist[nextY][nextX] > 0) 77 | continue; 78 | 79 | // ⓫ X가 아닌 지점만 이동 가능 80 | if (map[nextY][nextX] == 'X') 81 | continue; 82 | 83 | // ⓬ 거리 1증가 84 | dist[nextY][nextX] = dist[now.ny][now.nx] + 1; 85 | 86 | // ⓭ 다음 정점을 큐에 넣음 87 | queue.add(new Point(nextX, nextY)); 88 | 89 | // ⓮ 도착점에 도달하면 최단 거리를 반환 90 | if (nextX == end.nx && nextY == end.ny) 91 | return dist[end.ny][end.nx] - 1; 92 | } 93 | } 94 | 95 | // ⓯ 탐색을 종료할 때까지 도착 지점에 도달하지 못 했다면 -1 반환 96 | return -1; 97 | } 98 | 99 | } -------------------------------------------------------------------------------- /solution/40.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.Arrays; 3 | import java.util.PriorityQueue; 4 | 5 | public class Solution { 6 | 7 | private static class Node { 8 | int dest, cost; 9 | 10 | public Node(int dest, int cost) { 11 | this.dest = dest; 12 | this.cost = cost; 13 | } 14 | } 15 | 16 | public int solution(int N, int[][] road, int K) { 17 | // ❶ 인접 리스트를 저장할 ArrayList 배열 초기화 18 | ArrayList[] adjList = new ArrayList[N + 1]; 19 | for (int i = 1; i <= N; i++) { 20 | adjList[i] = new ArrayList<>(); 21 | } 22 | 23 | // ❷ road 정보를 인접 리스트로 저장 24 | for (int[] edge : road) { 25 | adjList[edge[0]].add(new Node(edge[1], edge[2])); 26 | adjList[edge[1]].add(new Node(edge[0], edge[2])); 27 | } 28 | 29 | int[] dist = new int[N + 1]; 30 | // ❸ 모든 노드의 거리 값을 무한대로 초기화 31 | Arrays.fill(dist, Integer.MAX_VALUE); 32 | 33 | // ❹ 우선순위 큐를 생성하고 시작 노드를 삽입 34 | PriorityQueue pq = new PriorityQueue<>((o1, o2) -> Integer.compare(o1.cost, o2.cost)); 35 | pq.add(new Node(1, 0)); 36 | dist[1] = 0; 37 | 38 | while (!pq.isEmpty()) { 39 | Node now = pq.poll(); 40 | 41 | if (dist[now.dest] < now.cost) 42 | continue; 43 | 44 | // ❺ 인접한 노드들의 최단 거리를 갱신하고 우선순위 큐에 추가 45 | for (Node next : adjList[now.dest]) { 46 | if (dist[next.dest] > now.cost + next.cost) { 47 | dist[next.dest] = now.cost + next.cost; 48 | pq.add(new Node(next.dest, dist[next.dest])); 49 | } 50 | } 51 | } 52 | 53 | int answer = 0; 54 | 55 | // ❻ dist 배열에서 K 이하인 값의 개수를 구하여 반환 56 | for (int i = 1; i <= N; i++) { 57 | if (dist[i] <= K) answer++; 58 | } 59 | 60 | return answer; 61 | } 62 | 63 | } -------------------------------------------------------------------------------- /solution/41.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayDeque; 2 | 3 | public class Solution { 4 | 5 | private static class Node { 6 | int x, y, direction, cost; 7 | 8 | public Node(int x, int y, int direction, int cost) { 9 | this.x = x; 10 | this.y = y; 11 | this.direction = direction; 12 | this.cost = cost; 13 | } 14 | } 15 | 16 | // 순서가 반드시 (0, -1), (-1, 0), (0, 1), (1, 0) 순서로 되어야합니다. 코너 계산에 필요함 17 | private static final int[] rx = {0, -1, 0, 1}; 18 | private static final int[] ry = {-1, 0, 1, 0}; 19 | 20 | private static int N; 21 | private static int[][][] visited; 22 | 23 | // ❶ 주어진 좌표가 보드의 범위 내에 있는지 확인 24 | private static boolean isValid(int x, int y) { 25 | return 0 <= x && x < N && 0 <= y && y < N; 26 | } 27 | 28 | // ❷ 주어진 좌표가 차단되었거나 이동할 수 없는지 확인 29 | private static boolean isBlocked(int[][] board, int x, int y) { 30 | return (x == 0 && y == 0) || !isValid(x, y) || board[x][y] == 1; 31 | } 32 | 33 | // ❸ 이전 방향과 현재 방향에 따라 비용 계산 34 | private static int calculateCost(int direction, int prevDirection, int cost) { 35 | if (prevDirection == -1 || (prevDirection - direction) % 2 == 0) 36 | return cost + 100; 37 | return cost + 600; 38 | } 39 | 40 | // ❹ 주어진 좌표와 방향이 아직 방문하지 않았거나 새 비용이 더 작은 경우 41 | private static boolean isShouldUpdate(int x, int y, int direction, int newCost) { 42 | return visited[x][y][direction] == 0 || visited[x][y][direction] > newCost; 43 | } 44 | 45 | public int solution(int[][] board) { 46 | ArrayDeque queue = new ArrayDeque<>(); 47 | queue.add(new Node(0, 0, -1, 0)); 48 | N = board.length; 49 | visited = new int[N][N][4]; 50 | 51 | int answer = Integer.MAX_VALUE; 52 | 53 | // ❺ 큐가 빌 때까지 반복 54 | while (!queue.isEmpty()) { 55 | Node now = queue.poll(); 56 | 57 | // ❻ 가능한 모든 방향에 대해 반복 58 | for (int i = 0; i < 4; i++) { 59 | int new_x = now.x + rx[i]; 60 | int new_y = now.y + ry[i]; 61 | 62 | // ❼ 이동할 수 없는 좌표는 건너뛰기 63 | if (isBlocked(board, new_x, new_y)) { 64 | continue; 65 | } 66 | 67 | int new_cost = calculateCost(i, now.direction, now.cost); 68 | 69 | // ❽ 도착지에 도달한 경우 최소 비용 업데이트 70 | if (new_x == N - 1 && new_y == N - 1) { 71 | answer = Math.min(answer, new_cost); 72 | } 73 | // ❾ 좌표와 방향이 아직 방문하지 않았거나 새 비용이 더 작은 경우 큐에 추가 74 | else if(isShouldUpdate(new_x, new_y, i, new_cost)) { 75 | queue.add(new Node(new_x, new_y, i, new_cost)); 76 | visited[new_x][new_y][i] = new_cost; 77 | } 78 | } 79 | } 80 | 81 | return answer; 82 | } 83 | 84 | } -------------------------------------------------------------------------------- /solution/42.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | 3 | public class Solution { 4 | 5 | private static boolean[] visited; 6 | private static ArrayList[] adjList; 7 | private static int N, answer; 8 | 9 | public static int solution(int n, int[][] wires) { 10 | N = n; 11 | answer = n - 1; 12 | 13 | // ❶ 전선의 연결 정보를 저장할 인접 리스트 초기화 14 | adjList = new ArrayList[n + 1]; 15 | for (int i = 1; i <= n; i++) { 16 | adjList[i] = new ArrayList<>(); 17 | } 18 | 19 | // ❷ 전선의 연결 정보를 인접 리스트에 저장 20 | for (int[] wire : wires) { 21 | adjList[wire[0]].add(wire[1]); 22 | adjList[wire[1]].add(wire[0]); 23 | } 24 | 25 | visited = new boolean[n + 1]; 26 | 27 | // ❸ 깊이 우선 탐색 시작 28 | dfs(1); 29 | 30 | return answer; 31 | } 32 | 33 | private static int dfs(int now) { 34 | visited[now] = true; 35 | 36 | // ❹ 자식 노드의 수를 저장하고 반환할 변수 선언 37 | int sum = 0; 38 | // ❺ 연결된 모든 전선을 확인 39 | for (int next : adjList[now]) { 40 | if (!visited[next]) { 41 | // ❻ (전체 노드 - 자식 트리의 노드 수) - (자식 트리의 노드 수) 의 절대값이 가장 작은 값을 구함 42 | int cnt = dfs(next); // 자식 트리가 가진 노드의 수 43 | answer = Math.min(answer, Math.abs(N - cnt * 2)); 44 | // ❼ 자식 노드의 수를 더함 45 | sum += cnt; 46 | } 47 | } 48 | 49 | // ❽ 전체 자식 노드의 수에 1(현재 now 노드)을 더해서 반환 50 | return sum + 1; 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /solution/43.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | 3 | public class Solution { 4 | 5 | public static void main(String[] args) { 6 | System.out.println(solution(5)); 7 | System.out.println(solution(2)); 8 | System.out.println(solution(7)); 9 | } 10 | 11 | // ❶ 조합 결과를 담을 리스트 12 | private static ArrayList> result; 13 | private static int n; 14 | private static void backtrack(int sum, ArrayList selectedNums, int start) { 15 | // ❷ 합이 10이 되면 결과 리스트에 추가 16 | if (sum == 10) { 17 | result.add(selectedNums); 18 | return; 19 | } 20 | 21 | // ❸ 다음에 선택할 수 있는 숫자들을 하나씩 선택하면서 22 | for (int i = start; i <= n; i++) { 23 | // ❹ 선택한 숫자의 합이 10보다 작거나 같으면 24 | if (sum + i <= 10) { 25 | ArrayList list = new ArrayList<>(selectedNums); 26 | list.add(i); 27 | // ❺ 백트래킹 메소드를 재귀적으로 호출합니다. 28 | backtrack(sum + i, list, i + 1); 29 | } 30 | } 31 | } 32 | 33 | // 이 부분을 변경해서 실행해보세요. 34 | private static ArrayList> solution(int N) { 35 | result = new ArrayList<>(); 36 | n = N; 37 | 38 | // ❻ 백트래킹 메소드 호출 39 | backtrack(0, new ArrayList<>(), 1); 40 | 41 | return result; 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /solution/44.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | public class Solution { 4 | 5 | public static void main(String[] args) { 6 | int[][] board1 = { 7 | {5, 3, 0, 0, 7, 0, 0, 0, 0}, 8 | {6, 0, 0, 1, 9, 5, 0, 0, 0}, 9 | {0, 9, 8, 0, 0, 0, 0, 6, 0}, 10 | {8, 0, 0, 0, 6, 0, 0, 0, 3}, 11 | {4, 0, 0, 8, 0, 3, 0, 0, 1}, 12 | {7, 0, 0, 0, 2, 0, 0, 0, 6}, 13 | {0, 6, 0, 0, 0, 0, 2, 8, 0}, 14 | {0, 0, 0, 4, 1, 9, 0, 0, 5}, 15 | {0, 0, 0, 0, 8, 0, 0, 7, 9} 16 | }; 17 | System.out.println(Arrays.deepToString(solution(board1))); 18 | 19 | int[][] board2 = { 20 | {0, 0, 0, 0, 0, 0, 0, 0, 0}, 21 | {0, 0, 0, 0, 0, 0, 0, 0, 0}, 22 | {0, 0, 0, 0, 0, 0, 0, 0, 0}, 23 | {0, 0, 0, 0, 0, 0, 0, 0, 0}, 24 | {0, 0, 0, 0, 0, 0, 0, 0, 0}, 25 | {0, 0, 0, 0, 0, 0, 0, 0, 0}, 26 | {0, 0, 0, 0, 0, 0, 0, 0, 0}, 27 | {0, 0, 0, 0, 0, 0, 0, 0, 0}, 28 | {0, 0, 0, 0, 0, 0, 0, 0, 0} 29 | }; 30 | System.out.println(Arrays.deepToString(solution(board2))); 31 | } 32 | 33 | private static class Block { 34 | int i, j; 35 | 36 | public Block(int i, int j) { 37 | this.i = i; 38 | this.j = j; 39 | } 40 | } 41 | 42 | private static int[][] Board; 43 | 44 | private static boolean isValid(int num, int row, int col) { 45 | // ❶ 현재 위치에 num이 들어갈 수 있는지 검사 46 | return !(inRow(num, row) || inCol(num, col) || inBox(num, row, col)); 47 | } 48 | 49 | private static boolean inRow(int num, int row) { 50 | // ❷ 해당 행에 num이 있는지 확인 51 | return Arrays.stream(Board[row]).anyMatch(n -> n == num); 52 | } 53 | 54 | private static boolean inCol(int num, int col) { 55 | // ❸ 해당 열에 num이 있는지 확인 56 | for (int i = 0; i < 9; i++) { 57 | if (Board[i][col] == num) return true; 58 | } 59 | return false; 60 | } 61 | 62 | private static boolean inBox(int num, int row, int col) { 63 | // ❹ 현재 위치의 3 x 3 박스에 num이 있는지 확인 64 | int boxRow = (row / 3) * 3; 65 | int boxCol = (col / 3) * 3; 66 | 67 | for (int i = boxRow; i < boxRow + 3; i++) { 68 | for (int j = boxCol; j < boxCol + 3; j++) { 69 | if (Board[i][j] == num) { 70 | return true; 71 | } 72 | } 73 | } 74 | 75 | return false; 76 | } 77 | 78 | private static Block findEmptyPosition() { 79 | // ❺ 스도쿠 보드에서 비어 있는 위치 반환 80 | for (int i = 0; i < 9; i++) { 81 | for (int j = 0; j < 9; j++) { 82 | if (Board[i][j] == 0) 83 | return new Block(i, j); 84 | } 85 | } 86 | return null; 87 | } 88 | 89 | private static boolean findSolution() { 90 | // ❻ 비어 있는 위치에 가능한 숫자를 넣어가며 스도쿠 해결 91 | Block emptyPos = findEmptyPosition(); 92 | // ❼ 빈칸이 없으면 스도쿠가 해결된 것으로 간주 93 | if (emptyPos == null) 94 | return true; 95 | 96 | int row = emptyPos.i; 97 | int col = emptyPos.j; 98 | 99 | for (int num = 1; num <= 9; num++) { 100 | if (isValid(num, row, col)) { 101 | Board[row][col] = num; 102 | // ❽ 다음 빈칸을 재귀 탐색 103 | if (findSolution()) { 104 | return true; 105 | } 106 | // ❾ 가능한 숫자가 없으면 원래의 0으로 되돌림 107 | Board[row][col] = 0; 108 | } 109 | } 110 | 111 | return false; 112 | } 113 | 114 | // 이 부분을 변경해서 실행해보세요. 115 | private static int[][] solution(int[][] board) { 116 | Board = board; 117 | findSolution(); 118 | return board; 119 | } 120 | 121 | } -------------------------------------------------------------------------------- /solution/45.java: -------------------------------------------------------------------------------- 1 | public class Solution { 2 | 3 | private static int answer; 4 | private static int[][] Dungeons; 5 | private static boolean[] visited; 6 | 7 | // 백트래킹을 위한 DFS 8 | private static void backtrack(int k, int cnt) { 9 | for (int i = 0; i < Dungeons.length; i++) { 10 | // ❶ 현재 피로도(k)가 i번째 던전의 최소 필요 피로도보다 크거나 같고, 11 | // i번째 던전을 방문한 적이 없다면 12 | if (!visited[i] && k >= Dungeons[i][0]) { 13 | visited[i] = true; // i번째 던전을 방문 처리 14 | // ❷ 현재까지의 최대 탐험 가능 던전 수와 15 | // i번째 던전에서 이동할 수 있는 최대 탐험 가능 던전 수 중 큰 값을 선택하여 업데이트 16 | backtrack(k - Dungeons[i][1], cnt + 1); 17 | answer = Math.max(answer, cnt + 1); 18 | visited[i] = false; // i번째 던전을 다시 방문 취소 19 | } 20 | } 21 | } 22 | 23 | public int solution(int k, int[][] dungeons) { 24 | answer = 0; 25 | Dungeons = dungeons; 26 | // ❸ 던전 방문 여부를 저장할 배열 27 | visited = new boolean[dungeons.length]; 28 | 29 | backtrack(k, 0); // ❹ DFS 메소드 수행 30 | 31 | return answer; 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /solution/46.java: -------------------------------------------------------------------------------- 1 | public class Solution { 2 | 3 | private static int N; 4 | private static boolean[] width; 5 | private static boolean[] diagonal1; 6 | private static boolean[] diagonal2; 7 | 8 | // ❶ 퀸이 서로 공격할 수 없는 위치에 놓이는 경우의 수를 구하는 함수 9 | private static int getAns(int y) { 10 | int ans = 0; 11 | // ❷ 모든 행에 대해서 퀸의 위치가 결장되었을 경우 12 | if (y == N) { 13 | // ❸ 해결 가능한 경우의 수를 1 증가시킴 14 | ans++; 15 | } 16 | else { 17 | // ❹ 현재 행에서 퀸이 놓일 수 있는 모든 위치를 시도 18 | for (int i = 0; i < N; i++) { 19 | // ❺ 해당 위치에 이미 퀸이 있는 경우, 대각선상에 퀸이 있는 경우 스킵 20 | if (width[i] || diagonal1[i + y] || diagonal2[i - y + N]) 21 | continue; 22 | 23 | // ❻ 해당 위치에 퀸을 놓음 24 | width[i] = diagonal1[i + y] = diagonal2[i - y + N] = true; 25 | // ❼ 다음 행으로 이동하여 재귀적으로 해결 가능한 경우의 수 찾기 26 | ans += getAns(y + 1); 27 | // ❽ 해당 위치에 놓인 퀸을 제거함 28 | width[i] = diagonal1[i + y] = diagonal2[i - y + N] = false; 29 | } 30 | } 31 | 32 | return ans; 33 | } 34 | 35 | public int solution(int n) { 36 | N = n; 37 | width = new boolean[n]; 38 | diagonal1 = new boolean[n * 2]; 39 | diagonal2 = new boolean[n * 2]; 40 | 41 | int answer = getAns(0); 42 | return answer; 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /solution/47.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | public class Solution { 4 | 5 | private static int max; 6 | private static int[] answer; 7 | private static int[] apeach; 8 | 9 | // ❶ 주어진 조합에서 각각의 점수 계산 10 | private static int getScore(int[] ryan) { 11 | int score = 0; 12 | for (int i = 0; i <= 10; i++) { 13 | if (ryan[i] + apeach[i] > 0) { 14 | score += ryan[i] > apeach[i] ? (10 - i) : -(10 - i); 15 | } 16 | } 17 | return score; 18 | } 19 | 20 | // ❷ 최대 차이와 라이언의 과녁 저장 21 | private static void calculateDiff(int[] ryan) { 22 | int score = getScore(ryan); 23 | if (max < score) { 24 | max = score; 25 | answer = ryan.clone(); 26 | } 27 | // 점수가 같으면 가장 낮은 점수를 더 많이 맞힌 경우를 찾음 28 | else if (max > 0 && max == score) { 29 | for (int i = 10; i >= 0; i--) { 30 | if(answer[i] != ryan[i]) { 31 | if (answer[i] < ryan[i]) { 32 | answer = ryan.clone(); 33 | } 34 | break; 35 | } 36 | } 37 | } 38 | } 39 | 40 | // ❸ 가능한 라이언의 과녁 점수 조합의 모든 경우를 구함 41 | private static void backtrack(int n, int idx, int[] ryan) { 42 | if (n == 0) { 43 | calculateDiff(ryan); 44 | return; 45 | } 46 | 47 | for (int i = idx; i <= 10; i++) { 48 | int cnt = i == 10 ? n : apeach[i] + 1; 49 | if (cnt > n) { 50 | continue; 51 | } 52 | ryan[i] = cnt; 53 | backtrack(n - cnt, i + 1, ryan); 54 | ryan[i] = 0; 55 | } 56 | } 57 | 58 | public static int[] solution(int n, int[] info) { 59 | apeach = info; 60 | max = 0; 61 | backtrack(n, 0, new int[11]); 62 | // ❹ 최대 차이가 0인 경우 -1 반환, 아니면 answer 반환 63 | return max == 0 ? new int[]{-1} : answer; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /solution/48.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | public class Solution { 4 | 5 | private static int length, answer; 6 | private static int[] Weak; 7 | private static boolean[] used; 8 | 9 | // ❶ dist 배열의 친구들로 모든 외벽이 점검 가능한지 확인 10 | private static boolean check(int[] dist) { 11 | // ❷ 점검을 시작하는 외벽을 0 부터 length 까지 전부 확인함 12 | for (int i = 0; i < length; i++) { 13 | int idx = i; 14 | // ❸ 각 친구가 점검 가능한 외벽을 모두 점검하며 진행 15 | for (int distance : dist) { 16 | int position = Weak[idx++] + distance; 17 | while (idx < Weak.length && Weak[idx] <= position) { 18 | idx++; 19 | } 20 | } 21 | // ❹ 모든 외벽을 점검 가능하면 true 반환 22 | if (idx - i >= length) 23 | return true; 24 | } 25 | // ❺ 모든 외벽을 점검할 수 없으면 false 반환 26 | return false; 27 | } 28 | 29 | // ❻ n개의 숫자를 나열하는 모든 경우의 수를 구함 30 | private static void backtrack(int n, int[] dist, int[] org) { 31 | if (n == org.length) { 32 | // ❼ 모든 외벽이 점검 가능하면 답 저장 33 | if (check(dist)) 34 | answer = n; 35 | return; 36 | } 37 | 38 | // ❽ 한 번 사용한 친구는 다시 사용하지 않도록 used 배열을 활용하여 백트래킹 39 | for (int i = 0; i < org.length; i++) { 40 | if (!used[i]) { 41 | used[i] = true; 42 | dist[n] = org[i]; 43 | backtrack(n + 1, dist, org); 44 | used[i] = false; 45 | } 46 | } 47 | } 48 | 49 | public static int solution(int n, int[] weak, int[] dist) { 50 | // ❾ 주어진 weak 지점들을 선형으로 만들어 줌 51 | length = weak.length; 52 | Weak = new int[length * 2]; 53 | for (int i = 0; i < 2; i++) { 54 | for (int j = 0; j < length; j++) { 55 | Weak[j + (i * length)] = weak[j] + (i * n); 56 | } 57 | } 58 | 59 | // ➓ 오름차순으로 정렬 60 | Arrays.sort(dist); 61 | answer = -1; // 답을 -1 로 초기화 62 | used = new boolean[dist.length]; // used 배열 생성 63 | 64 | // ⓫ 가장 점검 범위가 큰 친구부터 1명 씩 늘려가며 답을 탐색 65 | for (int i = 1; i <= dist.length; i++) { 66 | int[] org = new int[i]; 67 | System.arraycopy(dist, dist.length - i, org, 0, i); 68 | backtrack(0, new int[i], org); 69 | if (answer > 0) // 답을 찾았으면 종료해야 함 70 | break; 71 | } 72 | 73 | return answer; 74 | } 75 | 76 | } -------------------------------------------------------------------------------- /solution/49.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.Comparator; 3 | 4 | public class Solution { 5 | 6 | // 백트래킹을 위한 재귀 메소드의 반환값을 저장함 7 | private static class Result { 8 | boolean win; 9 | int step; 10 | 11 | public Result(boolean win, int step) { 12 | this.win = win; 13 | this.step = step; 14 | } 15 | } 16 | 17 | // ❶ 게임판의 행과 열의 개수를 저장합니다. 18 | private static int ROW, COL; 19 | 20 | // ❷ 이동할 수 있는 방향을 저장합니다. 상, 우, 하, 좌 순서로 저장되어 있습니다. 21 | private static final int[] DR = {0, 1, 0, -1}; 22 | private static final int[] DC = {-1, 0, 1, 0}; 23 | 24 | private static boolean[][] visited; 25 | 26 | private static int[][] Board; 27 | 28 | // ❸ 주어진 위치가 유효한 위치인지 확인하는 메소드입니다. 29 | private static boolean isVaildPos(int r, int c) { 30 | return 0 <= r && r < ROW && 0 <= c && c < COL; 31 | } 32 | 33 | // ❹ 재귀적으로 호출되는 메소드입니다. 34 | private static Result recursive(int[] alpha, int[] beta, int step) { 35 | // ❺ 현재 플레이어의 위치와 이동 가능한지 여부, 36 | // 상대 플레이어가 이긴 경우를 저장하는 변수들입니다. 37 | int[] now = step % 2 == 0 ? alpha : beta; 38 | boolean canMove = false; 39 | boolean isOpponentWinner = true; 40 | 41 | // ❻ 이긴 경우와 지는 경우를 저장하는 리스트입니다. 42 | ArrayList winSteps = new ArrayList<>(); 43 | ArrayList loseSteps = new ArrayList<>(); 44 | 45 | // ❼ 현재 위치에서 이동할 수 있는 모든 방향으로 이동해봅니다. 46 | for (int i = 0; i < 4; i++) { 47 | int nr = now[0] + DR[i]; 48 | int nc = now[1] + DC[i]; 49 | // ❽ 이동할 수 있는 위치인 경우 50 | if (isVaildPos(nr, nc) && !visited[nr][nc] && Board[nr][nc] == 1) { 51 | canMove = true; 52 | // ❾ 두 플레이어의 위치가 같으면 A 플레이어가 이긴 것이므로 true와 step + 1을 반환합니다. 53 | if (alpha[0] == beta[0] && alpha[1] == beta[1]) 54 | return new Result(true, step + 1); 55 | 56 | // ➓ 재귀적으로 호출하여 이긴 여부와 남은 턴 수를 가져옵니다. 57 | visited[now[0]][now[1]] = true; 58 | Result result = step % 2 == 0 ? recursive(new int[]{nr, nc}, beta, step + 1) 59 | : recursive(alpha, new int[]{nr, nc}, step + 1); 60 | visited[now[0]][now[1]] = false; 61 | 62 | // ⓫ 상대 플레이어가 이긴 경우만 true로 유지합니다. 63 | isOpponentWinner &= result.win; 64 | // ⓬ 이긴 경우와 지는 경우를 저장합니다. 65 | if (result.win) 66 | winSteps.add(result.step); 67 | else 68 | loseSteps.add(result.step); 69 | } 70 | } 71 | 72 | // ⓭ 이동할 수 있는 위치가 없는 경우 73 | if (!canMove) 74 | return new Result(false, step); 75 | // ⓮ 상대 플레이어가 이긴 경우 76 | if (isOpponentWinner) 77 | return new Result(false, winSteps.stream().max(Comparator.comparingInt(o -> o)).get()); 78 | // ⓯ 현재 플레이어가 이긴 경우 79 | return new Result(true, loseSteps.stream().min(Comparator.comparingInt(o -> o)).get()); 80 | } 81 | 82 | public static int solution(int[][] board, int[] aloc, int[] bloc) { 83 | Board = board; 84 | ROW = board.length; 85 | COL = board[0].length; 86 | visited = new boolean[ROW][COL]; 87 | // 16 A 플레이어가 이길 때까지 걸리는 최소 턴 수를 반환합니다. 88 | return recursive(aloc, bloc, 0).step; 89 | } 90 | 91 | } -------------------------------------------------------------------------------- /solution/50.java: -------------------------------------------------------------------------------- 1 | public class Solution { 2 | 3 | public static void main(String[] args) { 4 | System.out.println(solution("hello")); 5 | System.out.println(solution("algorithm")); 6 | } 7 | 8 | // 이 부분을 변경해서 실행해보세요. 9 | private static String solution(String s) { 10 | int[] counts = new int[26]; // ❶ 알파벳 개수(26개)만큼 빈도수 배열 생성 11 | 12 | // ❷ 문자열의 각 문제에 대한 빈도수를 count배열에 저장 13 | for (char c : s.toCharArray()) { 14 | counts[c - 'a']++; 15 | } 16 | 17 | // ❸ 빈도수 배열을 순회화면서 정렬된 문자열을 생성 18 | StringBuilder sortedStr = new StringBuilder(); 19 | for (int i = 0; i < 26; i++) { 20 | for (int j = 0; j < counts[i]; j++) { 21 | sortedStr.append((char)(i + 'a')); 22 | } 23 | } 24 | 25 | return sortedStr.toString(); 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /solution/51.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | public class Solution { 4 | 5 | public static void main(String[] args) { 6 | System.out.println(Arrays.toString(solution(new int[]{1, 3, 5}, new int[]{2, 4, 6}))); 7 | System.out.println(Arrays.toString(solution(new int[]{1, 2, 3}, new int[]{4, 5, 6}))); 8 | } 9 | 10 | // 이 부분을 변경해서 실행해보세요. 11 | private static int[] solution(int[] arr1, int[] arr2) { 12 | // 정렬된 배열을 저장할 배열 생성 13 | int[] merged = new int[arr1.length + arr2.length]; 14 | int k = 0, i = 0, j = 0; // 3개 배열의 인덱스 초기화 15 | 16 | // 두 배열을 순회하면서 정렬된 배열을 생성 17 | while (i < arr1.length && j < arr2.length) { 18 | merged[k++] = arr1[i] <= arr2[j] ? arr1[i++] : arr2[j++]; 19 | } 20 | 21 | // arr1 이나 arr2 중 남아 있는 원소들을 정렬된 배열 뒤에 추가 22 | while (i < arr1.length) { 23 | merged[k++] = arr1[i++]; 24 | } 25 | while (j < arr2.length) { 26 | merged[k++] = arr2[j++]; 27 | } 28 | 29 | return merged; 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /solution/52.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | public class Solution { 4 | 5 | public String[] solution(String[] strings, int n) { 6 | Arrays.sort(strings, (o1, o2) -> o1.charAt(n) == o2.charAt(n) ? o1.compareTo(o2) : Character.compare(o1.charAt(n), o2.charAt(n))); 7 | return strings; 8 | } 9 | 10 | } -------------------------------------------------------------------------------- /solution/53.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | import java.util.Collections; 3 | 4 | public class Solution { 5 | 6 | public long solution(long n) { 7 | // ❶ 정수 n을 문자열로 변환하고 각 자릿수를 배열로 저장합니다. 8 | String[] digits = String.valueOf(n).split(""); 9 | 10 | // ❷ 내림차순으로 정렬합니다. 11 | Arrays.sort(digits, Collections.reverseOrder()); 12 | 13 | // ❸ 정렬된 숫자를 다시 하나의 문자열로 합칩니다. 14 | StringBuilder sb = new StringBuilder(); 15 | for (String digit : digits) 16 | sb.append(digit); 17 | 18 | // ❹ 문자열을 long형으로 변환하여 반환합니다. 19 | return Long.parseLong(sb.toString()); 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /solution/54.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | public class Solution { 4 | 5 | public int[] solution(int[] array, int[][] commands) { 6 | int[] answer = new int[commands.length]; 7 | 8 | for (int c = 0; c < commands.length; c++) { 9 | int i = commands[c][0]; 10 | int j = commands[c][1]; 11 | int k = commands[c][2]; 12 | 13 | // ❶ i번째 부터 j번째 까지 자르기 14 | int[] slicedArr = Arrays.copyOfRange(array, i - 1, j); 15 | // ❷ 자른 배열을 정렬하기 16 | Arrays.sort(slicedArr); 17 | // ❸ k번째 원소 구하기 18 | answer[c] = slicedArr[k - 1]; 19 | } 20 | 21 | return answer; 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /solution/55.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | 3 | public class Solution { 4 | 5 | public String solution(int[] numbers) { 6 | // ❶ int형 정수 배열을 문자열로 바꾸어 list에 저장합니다. 7 | ArrayList list = new ArrayList<>(); 8 | for (int number : numbers) { 9 | list.add(String.valueOf(number)); 10 | } 11 | 12 | // ❷ 조합하여 비교하여 더 큰 수를 기준으로 내림차순 정렬합니다. 13 | list.sort((o1, o2) -> { 14 | int a = Integer.parseInt(o1 + o2); 15 | int b = Integer.parseInt(o2 + o1); 16 | return Integer.compare(b, a); 17 | }); 18 | 19 | // ❸ 정렬된 수를 나열하여 문자열로 만듭니다. 20 | StringBuilder sb = new StringBuilder(); 21 | for (String s : list) { 22 | sb.append(s); 23 | } 24 | 25 | // ❹ 문자열을 반환합니다. 맨앞에 "0" 이 있는 경우는 "0"만 반환합니다. 26 | return sb.charAt(0) == '0' ? "0" : sb.toString(); 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /solution/56.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | import java.util.HashSet; 3 | 4 | public class Solution { 5 | 6 | public int[] solution(String s) { 7 | // ❶ 문자열 s에서 대괄호를 제거하고 ","을 기준으로 나누어 배열에 저장한 후 길이 기준으로 오름차순 정렬합니다. 8 | s = s.substring(0, s.length() - 2).replace("{", ""); 9 | String[] arr = s.split("},"); 10 | Arrays.sort(arr, (o1, o2) -> Integer.compare(o1.length(), o2.length())); 11 | 12 | HashSet set = new HashSet<>(); 13 | int[] answer = new int[arr.length]; 14 | 15 | // ❷ 각 원소를 순회하면서 이전 원소와 차이 나는 부분을 구합니다. 16 | for (int i = 0; i < arr.length; i++) { 17 | String[] numbers = arr[i].split(","); 18 | for (String number : numbers) { 19 | if (!set.contains(number)) { 20 | answer[i] = Integer.parseInt(number); 21 | set.add(number); 22 | } 23 | } 24 | } 25 | 26 | return answer; 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /solution/57.java: -------------------------------------------------------------------------------- 1 | import java.util.PriorityQueue; 2 | 3 | public class Solution { 4 | 5 | private static class Node { 6 | int i, j, cost; 7 | 8 | public Node(int i, int j, int cost) { 9 | this.i = i; 10 | this.j = j; 11 | this.cost = cost; 12 | } 13 | } 14 | 15 | public int solution(int[][] land, int height) { 16 | int answer = 0; 17 | int n = land.length; 18 | 19 | // ❶ 주변 노드 탐색을 위한 di, dj 20 | int[] di = {-1, 0, 1, 0}; 21 | int[] dj = {0, 1, 0, -1}; 22 | 23 | boolean[][] visited = new boolean[n][n]; 24 | 25 | // ❷ 시작 노드 추가 26 | PriorityQueue pq = new PriorityQueue<>((o1, o2) -> Integer.compare(o1.cost, o2.cost)); 27 | pq.add(new Node(0, 0, 0)); 28 | 29 | // ❸ BFS + 우선순위 큐로 다음 노드 관리 30 | while (!pq.isEmpty()) { 31 | Node now = pq.poll(); 32 | // ❹ 아직 방문하지 않은 경로만 탐색 33 | if (visited[now.i][now.j]) 34 | continue; 35 | 36 | visited[now.i][now.j] = true; 37 | // ❺ 현재까지 비용을 합산 38 | answer += now.cost; 39 | 40 | for (int i = 0; i < 4; i++) { 41 | int ni = now.i + di[i]; 42 | int nj = now.j + dj[i]; 43 | 44 | // ❻ 유효한 인덱스가 아닐 경우 45 | if (!(0 <= ni && ni < n && 0 <= nj && nj < n)) 46 | continue; 47 | 48 | int tempCost = Math.abs(land[now.i][now.j] - land[ni][nj]); 49 | // ❼ 입력으로 주어진 height 보다 높이차가 큰 경우 50 | int newCost = tempCost > height ? tempCost : 0; 51 | // ❽ 다음 경로를 add 52 | pq.add(new Node(ni, nj, newCost)); 53 | } 54 | } 55 | 56 | return answer; 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /solution/58.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | public class Solution { 4 | 5 | public boolean solution(String[] phone_book) { 6 | // ❶ 전화번호부 정렬 7 | Arrays.sort(phone_book); 8 | 9 | // ❷ 전화번호부에서 연속된 두 개의 전화번호 비교 10 | for (int i = 0; i < phone_book.length - 1; i++) { 11 | if (phone_book[i + 1].startsWith(phone_book[i])) 12 | return false; 13 | } 14 | 15 | // ❸ 모든 전화번호를 비교한 후에도 반환되지 않았다면, 접두어가 없는 경우이므로 true 반환 16 | return true; 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /solution/59.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | public class Solution { 4 | 5 | public static void main(String[] args) { 6 | int[][] arr1 = { 7 | {1, 2, 3, 4}, 8 | {5, 6, 7, 8}, 9 | {9, 10, 11, 12}, 10 | {13, 14, 15, 16} 11 | }; 12 | int n1 = 1; 13 | System.out.println(Arrays.deepToString(solution(arr1, n1))); 14 | int[][] arr2 = { 15 | {1, 2, 3, 4}, 16 | {5, 6, 7, 8}, 17 | {9, 10, 11, 12}, 18 | {13, 14, 15, 16} 19 | }; 20 | int n2 = 2; 21 | System.out.println(Arrays.deepToString(solution(arr2, n2))); 22 | } 23 | 24 | // ❶ 2차원 배열을 인자로 받고, 90도 회전시키는 메소드 25 | private static int[][] rotate90(int[][] arr) { 26 | // ❷ 배열의 크기 저장 27 | int n = arr.length; 28 | 29 | // ❸ 배열의 크기와 동일한 2차원 배열 생성(초기값은 0) 30 | int[][] rotatedArr = new int[n][n]; 31 | 32 | // ❹ 배열을 90도 회전 33 | for (int i = 0; i < n; i++) { 34 | for (int j = 0; j < n; j++) { 35 | rotatedArr[j][n - i - 1] = arr[i][j]; 36 | } 37 | } 38 | 39 | // ❺ 90도로 회전한 배열 반환 40 | return rotatedArr; 41 | } 42 | 43 | // 이 부분을 변경해서 실행해보세요. 44 | private static int[][] solution(int[][] arr, int n) { 45 | // ❻ 90도 회전 메소드 호출 46 | for (int i = 0; i < n; i++) { 47 | arr = rotate90(arr); 48 | } 49 | return arr; 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /solution/60.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | public class Solution { 4 | 5 | public static void main(String[] args) { 6 | int[][] matrix1_1 = { 7 | {1, 2, 3}, 8 | {4, 5, 6}, 9 | {7, 8, 9} 10 | }; 11 | int[][] matrix2_1 = { 12 | {9, 8, 7}, 13 | {6, 5, 4}, 14 | {3, 2, 1} 15 | }; 16 | System.out.println(Arrays.deepToString(solution(matrix1_1, matrix2_1))); 17 | 18 | int[][] matrix1_2 = { 19 | {2, 4, 6}, 20 | {1, 3, 5}, 21 | {7, 8, 9} 22 | }; 23 | int[][] matrix2_2 = { 24 | {9, 1, 2}, 25 | {4, 5, 6}, 26 | {7, 3, 8} 27 | }; 28 | System.out.println(Arrays.deepToString(solution(matrix1_2, matrix2_2))); 29 | } 30 | 31 | private static int[][] multiplyMatrices(int[][] matrix1, int[][] matrix2) { 32 | // ❶ 결과 행렬을 0으로 초기화합니다. 33 | int[][] result = new int[3][3]; 34 | 35 | // ❷ 행렬 곱셈을 수행합니다. 36 | for (int i = 0; i < 3; i++) { 37 | for (int j = 0; j < 3; j++) { 38 | for (int k = 0; k < 3; k++) { 39 | result[i][j] += matrix1[i][k] * matrix2[k][j]; 40 | } 41 | } 42 | } 43 | 44 | return result; 45 | } 46 | 47 | private static int[][] transposeMatrix(int[][] matrix) { 48 | // ❸ 결과 행렬을 0으로 초기화합니다. 49 | int[][] result = new int[3][3]; 50 | 51 | // 전치 행렬을 계산합니다. 52 | for (int i = 0; i < 3; i++) { 53 | for (int j = 0; j < 3; j++) { 54 | result[j][i] = matrix[i][j]; 55 | } 56 | } 57 | 58 | return result; 59 | } 60 | 61 | // 이 부분을 변경해서 실행해보세요. 62 | private static int[][] solution(int[][] matrix1, int[][] matrix2) { 63 | // 주어진 두 행렬을 곱합니다. 64 | int[][] multiplied = multiplyMatrices(matrix1, matrix2); 65 | 66 | // 곱셈 결과의 전치 행렬을 계산합니다. 67 | int[][] transposed = transposeMatrix(multiplied); 68 | 69 | return transposed; 70 | } 71 | 72 | } -------------------------------------------------------------------------------- /solution/61.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | public class Solution { 4 | 5 | public static void main(String[] args) { 6 | System.out.println(Arrays.deepToString(solution(3))); 7 | System.out.println(Arrays.deepToString(solution(4))); 8 | } 9 | 10 | // 이 부분을 변경해서 실행해보세요. 11 | private static int[][] solution(int n) { 12 | // ❶ n 크기의 2차원 배열 생성 13 | int[][] snailArray = new int[n][n]; 14 | 15 | int num = 1; // ❷ 달팽이 수열의 시작 숫자 16 | 17 | // ❸ 행과 열의 시작과 끝 인덱스를 설정 18 | int startRow = 0, endRow = n - 1; 19 | int startCol = 0, endCol = n - 1; 20 | 21 | while (startRow <= endRow && startCol <= endCol) { 22 | // ❹ 첫 번째 행 채우기 23 | for (int i = startCol; i <= endCol; i++) { 24 | snailArray[startRow][i] = num++; 25 | } 26 | startRow++; 27 | 28 | // ❺ 마지막 열 채우기 29 | for (int i = startRow; i <= endRow; i++) { 30 | snailArray[i][endCol] = num++; 31 | } 32 | endCol--; 33 | 34 | // ❻ 마지막 행 채우기 35 | if (startRow <= endRow) { 36 | for (int i = endCol; i >= startCol; i--) { 37 | snailArray[endRow][i] = num++; 38 | } 39 | endRow--; 40 | } 41 | 42 | // ❼ 첫 번째 열 채우기 43 | if (startCol <= endCol) { 44 | for (int i = endRow; i >= startRow; i--) { 45 | snailArray[i][startCol] = num++; 46 | } 47 | startCol++; 48 | } 49 | } 50 | 51 | return snailArray; 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /solution/62.java: -------------------------------------------------------------------------------- 1 | public class Solution { 2 | 3 | public int[] solution(String s) { 4 | // ❶ 이진 변환 횟수를 저장하는 변수 5 | int countTransform = 0; 6 | // ❷ 제거된 모든 0의 개수를 저장하는 변수 7 | int countZero = 0; 8 | 9 | // ❸ s가 '1'이 아닌 동안 계속 반복 10 | while (!s.equals("1")) { 11 | // ❹ 이진 변환 횟수를 1 증가 12 | countTransform++; 13 | // ❺ s에서 '0'의 개수를 세어 countZero에 누적 14 | int zero = s.replace("1", "").length(); 15 | countZero += zero; 16 | // ❻ s에서 '1'의 개수를 세고, 이를 이진수로 반환 17 | // Integer.toBinaryString() 메소드를 활용 18 | s = Integer.toBinaryString(s.length() - zero); 19 | } 20 | 21 | // ❼ 이진 변환 횟수와 제거된 모든 '0'의 개수를 배열에 담아 반환 22 | return new int[]{countTransform, countZero}; 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /solution/63.java: -------------------------------------------------------------------------------- 1 | import java.util.HashMap; 2 | import java.util.HashSet; 3 | 4 | public class Solution { 5 | 6 | public int solution(int[] topping) { 7 | // ❶ 결과값을 저장할 변수 초기화 8 | int answer = 0; 9 | 10 | // ❷ 토핑의 개수를 세어서 해시맵에 저장 11 | HashMap toppingMap = new HashMap<>(); 12 | for (int t : topping) { 13 | toppingMap.put(t, toppingMap.getOrDefault(t, 0) + 1); 14 | } 15 | 16 | // ❸ 토핑의 종류를 저장할 해시셋 17 | HashSet toppingSet = new HashSet<>(); 18 | 19 | // ❹ 롤케이크를 하나씩 해시셋에 넣으면서 확인 20 | for (int t : topping) { 21 | // ❺ 해시셋에 토핑을 추가하고, 해당 토핑의 전체 개수를 해시맵에서 줄임 22 | toppingSet.add(t); 23 | toppingMap.put(t, toppingMap.get(t) - 1); 24 | 25 | // ❻ 토핑의 전체 개수가 0이면 해시맵에서 제거 26 | if (toppingMap.get(t) == 0) 27 | toppingMap.remove(t); 28 | 29 | // ❼ 토핑의 종류의 수가 같다면 30 | if (toppingSet.size() == toppingMap.size()) 31 | answer++; 32 | } 33 | 34 | // ❽ 공평하게 나눌 수 있는 방법의 수 반환 35 | return answer; 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /solution/64.java: -------------------------------------------------------------------------------- 1 | public class Solution { 2 | 3 | public int[] solution(int brown, int yellow) { 4 | // ❶ 격자의 총 개수 (파란색 격자 + 흰색 격자) 5 | int totalSize = brown + yellow; 6 | // ❷ 세로 길이의 범위는 3부터 (갈색 격자 + 노란색 격자)의 제곱근 7 | int sqrt = (int)Math.sqrt(totalSize); 8 | for (int vertical = 3; vertical <= sqrt; vertical++) { 9 | // ❸ 사격형 구성이 되는지 확인 10 | if (totalSize % vertical == 0) { 11 | // ❹ 사각형의 가로 길이 12 | int horizontal = (int)(totalSize / vertical); 13 | // ❺ 카펫 형태로 만들 수 있는지 확인 14 | if (brown == (horizontal + vertical - 2) * 2) { 15 | return new int[]{horizontal, vertical}; // ❻ [가로 길이, 세로 길이] 16 | } 17 | } 18 | } 19 | return new int[]{}; // ❼ 만약 답을 찾지 못했다면 빈 리스트를 반환 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /solution/65.java: -------------------------------------------------------------------------------- 1 | public class Solution { 2 | 3 | public int solution(int n) { 4 | return Integer.toBinaryString(n).replace("0","").length(); 5 | } 6 | 7 | } -------------------------------------------------------------------------------- /solution/66.java: -------------------------------------------------------------------------------- 1 | import java.util.HashMap; 2 | 3 | public class Solution { 4 | 5 | // ❶ 보드의 경계좌표를 벗어나는지 확인하는 메소드 6 | private static boolean isInBounds(int x, int y, int dx, int dy) { 7 | return Math.abs(x + dx) <= width && Math.abs(y + dy) <= height; 8 | } 9 | 10 | private static int width, height; 11 | 12 | public int[] solution(String[] keyinput, int[] board) { 13 | // ❷ 캐릭터의 초기 위치 14 | int x = 0, y = 0; 15 | // ❸ 각 방향에 대한 움직임 16 | HashMap moves = new HashMap<>(); 17 | moves.put("up", new int[]{0, 1}); 18 | moves.put("down", new int[]{0, -1}); 19 | moves.put("left", new int[]{-1, 0}); 20 | moves.put("right", new int[]{1, 0}); 21 | // ❹ 게임 경계좌표 22 | width = board[0] / 2; 23 | height = board[1] / 2; 24 | 25 | for (String key : keyinput) { 26 | // ❺ 방향키에 따른 오프셋 27 | int dx = moves.get(key)[0]; 28 | int dy = moves.get(key)[1]; 29 | // ❻ 게임 맵의 크기를 벗어나지 않는지 확인 30 | if (isInBounds(x, y, dx, dy)) { 31 | x += dx; 32 | y += dy; 33 | } 34 | } 35 | 36 | // ❼ 캐릭터의 위치를 반환합니다. 37 | return new int[]{x, y}; 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /solution/67.java: -------------------------------------------------------------------------------- 1 | public class Solution { 2 | 3 | public static void main(String[] args) { 4 | System.out.println(solution("ABCBDAB", "BDCAB")); 5 | System.out.println(solution("AGGTAB", "GXTXAYB")); 6 | } 7 | 8 | // 이 부분을 변경해서 실행해보세요. 9 | private static int solution(String str1, String str2) { 10 | // ❶ 두 문자열의 길이를 저장 11 | int m = str1.length(); 12 | int n = str2.length(); 13 | 14 | // ❷ LCS를 저장할 테이블 초기화 15 | int[][] dp = new int[m + 1][n + 1]; 16 | 17 | // ❸ 동적 프로그래밍을 통해 LCS 길이 계산 18 | for (int i = 1; i <= m; i++) { 19 | for (int j = 1; j <= n; j++) { 20 | // ❹ 현재 비교하는 문자가 같으면 21 | if (str1.charAt(i - 1) == str2.charAt(j - 1)) { 22 | dp[i][j] = dp[i - 1][j - 1] + 1; 23 | } 24 | // ❺ 현재 비교하는 문자가 같지 않으면 25 | else { 26 | dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); 27 | } 28 | } 29 | } 30 | 31 | // ❻ LCS 길이 반환 32 | return dp[m][n]; 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /solution/68.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | public class Solution { 4 | 5 | public static void main(String[] args) { 6 | System.out.println(lis(new int[]{1, 4, 2, 3, 1, 5, 7, 3})); 7 | System.out.println(lis(new int[]{3, 2, 1})); 8 | } 9 | 10 | // 이 부분을 변경해서 실행해보세요. 11 | private static int lis(int[] nums) { 12 | int n = nums.length; 13 | 14 | // ❶ dp[i]는 nums[i]를 마지막으로 하는 LIS의 길이를 저장하는 배열입니다. 15 | int[] dp = new int[n]; 16 | Arrays.fill(dp, 1); 17 | 18 | for (int i = 1; i < n; i++) { 19 | for (int j = 0; j < i; j++) { 20 | // ❷ num[i]와 nums[j]를 비교하여, nums[i]가 더 큰 경우에만 처리합니다. 21 | if (nums[i] > nums[j]) { 22 | // ❸ nums[i]를 이용하여 만든 부분 수열의 길이와 23 | // nums[j]를 이용하여 만든 부분 수열의 길이 + 1 중 최댓값을 저장합니다. 24 | dp[i] = Math.max(dp[i], dp[j] + 1); 25 | } 26 | } 27 | } 28 | 29 | // ❹ dp 배열에서 최댓값을 찾아 최장 증가 부분 수열의 길이를 반환합니다. 30 | return Arrays.stream(dp).max().getAsInt(); 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /solution/69.java: -------------------------------------------------------------------------------- 1 | public class Solution { 2 | 3 | public static void main(String[] args) { 4 | int[][] arr1 = {{1, 3, 3, 2}, {2, 1, 4, 1}, {1, 5, 2, 3}}; 5 | System.out.println(solution(arr1)); 6 | int[][] arr2 = {{1, 7, 13, 2, 6}, {2, -4, 2, 5, 4}, {5, 3, 5, -3, 1}}; 7 | System.out.println(solution(arr2)); 8 | } 9 | 10 | // 이 부분을 변경해서 실행해보세요. 11 | private static int solution(int[][] arr) { 12 | // ❶ 입력 배열의 열의 개수를 저장합니다. 13 | int n = arr[0].length; 14 | // ❷ dp 배열을 초기화합니다. 4행 n열의 2차원 배열입니다. 15 | int[][] dp = new int[4][n]; 16 | 17 | // 각 열에서 선택 가능한 4가지 조약돌 배치 패턴에 대해 첫 번째 열의 가중치를 초기화합니다. 18 | // ❸ 0: 상단, 1: 중앙, 2: 하단, 3: 상단과 하단 19 | dp[0][0] = arr[0][0]; 20 | dp[1][0] = arr[1][0]; 21 | dp[2][0] = arr[2][0]; 22 | dp[3][0] = arr[0][0] + arr[2][0]; 23 | 24 | // ❹ 두 번째 열부터 마지막 열까지 각 열에서 선택 가능한 4가지 조약돌 배치 패턴에 대해 25 | // 최대 가중치를 계산합니다. 26 | for (int i = 1; i < n; i++) { 27 | // 패턴 0이 선택된 경우, 이전은 패턴 {1, 2} 가능 28 | dp[0][i] = arr[0][i] + Math.max(dp[1][i - 1], dp[2][i - 1]); 29 | // 패턴 1이 선택된 경우, 이전은 패턴 {0, 2, 3} 가능 30 | dp[1][i] = arr[1][i] + Math.max(dp[0][i - 1], Math.max(dp[2][i - 1], dp[3][i - 1])); 31 | // 패턴 2이 선택된 경우, 이전은 패턴 {0, 1} 가능 32 | dp[2][i] = arr[2][i] + Math.max(dp[0][i - 1], dp[1][i - 1]); 33 | // 패턴 3이 선택된 경우, 이전은 패턴 {1} 가능 34 | dp[3][i] = arr[0][i] + arr[2][i] + dp[1][i - 1]; 35 | } 36 | 37 | // ❺ 마지막 열에서 선택 가능한 4가지 조약돌 배치 패턴 중 최대 가중치를 반환합니다. 38 | return Math.max(Math.max(dp[0][n - 1], dp[1][n - 1]), Math.max(dp[2][n - 1], dp[3][n - 1])); 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /solution/70.java: -------------------------------------------------------------------------------- 1 | public class Solution { 2 | 3 | public int solution(int n) { 4 | int[] fibo = new int[n + 1]; 5 | fibo[0] = 0; 6 | fibo[1] = 1; 7 | for (int i = 2; i <= n; i++) { 8 | fibo[i] = (fibo[i - 1] + fibo[i - 2]) % 1234567; 9 | } 10 | return fibo[n]; 11 | } 12 | 13 | } -------------------------------------------------------------------------------- /solution/71.java: -------------------------------------------------------------------------------- 1 | public class Solution { 2 | 3 | public int solution(int n) { 4 | // ❶ 동적 계획법을 위한 배열 초기화 5 | // dp[i]는 가로 길이가 i일 때 바닥을 채우는 방법의 수 6 | int[] dp = new int[n + 1]; 7 | dp[1] = 1; 8 | dp[2] = 2; 9 | 10 | // ❷ 가로 길이가 3부터 n까지의 각각의 경우에 대해 바닥을 채우는 방법의 수를 구함 11 | for (int i = 3; i <= n; i++) { 12 | // ❸ dp[i]는 dp[i - 1]과 dp[i - 2]를 더한 값 13 | dp[i] = (dp[i - 1] + dp[i - 2]) % 1_000_000_007; 14 | } 15 | // ❹ 바닥의 가로 길이가 n일 때 바닥을 채우는 바업의 수인 dp[n]을 반환 16 | return dp[n]; 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /solution/72.java: -------------------------------------------------------------------------------- 1 | public class Solution { 2 | 3 | public int solution(int[][] triangle) { 4 | int n = triangle.length; 5 | int[][] dp = new int[n][n]; // ❶ dp 배열 초기화 6 | 7 | // ❷ dp 배열의 맨 아래쪽 라인 초기화 8 | for (int i = 0; i < n; i++) { 9 | dp[n - 1][i] = triangle[n - 1][i]; 10 | } 11 | 12 | // ❸ 아래쪽 라인부터 올라가면서 dp 배열 채우기 13 | for (int i = n - 2; i >= 0; i--) { 14 | for (int j = 0; j <= i; j++) { 15 | dp[i][j] = Math.max(dp[i + 1][j], dp[i + 1][j + 1]) + triangle[i][j]; 16 | } 17 | } 18 | 19 | return dp[0][0]; // 꼭대기에서의 최댓값 반환 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /solution/73.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | public class Solution { 4 | 5 | int solution(int[][] land) { 6 | // ❶ 각 행마다 이전 행에서의 최대 점수를 더해가며 최대 점수를 구합니다. 7 | for (int i = 1; i < land.length; i++) { 8 | for (int j = 0; j < 4; j++) { 9 | // ❷ 이전 행에서 현재 열의 값을 제외한 나머지 열들 중에서 가장 큰 값을 더해줍니다. 10 | int max = 0; 11 | for (int k = 0; k < 4; k++) { 12 | if (j != k) max = Math.max(max, land[i - 1][k]); 13 | } 14 | land[i][j] += max; 15 | } 16 | } 17 | 18 | return Arrays.stream(land[land.length - 1]).max().getAsInt(); 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /solution/74.java: -------------------------------------------------------------------------------- 1 | public class Solution { 2 | 3 | public int solution(int[] money) { 4 | // ❶ 점화식에 필요한 변수를 초기화 5 | int n = money.length; 6 | int[] dp1 = new int[n]; 7 | int[] dp2 = new int[n]; 8 | 9 | // ❷ 첫 번째 집을 도둑질하는 경우 10 | dp1[0] = money[0]; 11 | dp1[1] = money[0]; 12 | for (int i = 2; i < n - 1; i++) { 13 | dp1[i] = Math.max(dp1[i - 1], dp1[i - 2] + money[i]); 14 | } 15 | 16 | // ❸ 첫 번째 집을 도둑질하지 않는 경우 17 | dp2[1] = money[1]; 18 | for (int i = 2; i < n; i++) { 19 | dp2[i] = Math.max(dp2[i - 1], dp2[i - 2] + money[i]); 20 | } 21 | 22 | // ❹ 두 경우 중 최댓값 찾기 23 | return Math.max(dp1[n - 2], dp2[n - 1]); 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /solution/75.java: -------------------------------------------------------------------------------- 1 | public class Solution { 2 | 3 | public int solution(int [][]board) { 4 | // ❶ 주어진 2차원 보드의 행과 열의 개수를 변수에 저장합니다. 5 | int row = board.length; 6 | int col = board[0].length; 7 | 8 | // ❷ 각 행과 열을 순회하며 최적의 정사각형을 찾습니다. 9 | for (int i = 1; i < row; i++) { 10 | for (int j = 1; j < col; j++) { 11 | // ❸ 현재 위치의 값이 1인 경우를 확인합니다. 12 | if (board[i][j] == 1) { 13 | // ❹ 현재 위치에서 위, 왼쪽, 대각선 왼쪽 위의 값들을 가져옵니다. 14 | int up = board[i - 1][j]; 15 | int left = board[i][j - 1]; 16 | int upLeft = board[i - 1][j - 1]; 17 | // ❺ 현재 위치의 값을 이전 위치들의 값들 중 18 | // 가장 작은 값에 1을 더한 값으로 업데이트 합니다. 19 | board[i][j] += Math.min(up, Math.min(upLeft, left)); 20 | } 21 | } 22 | } 23 | 24 | int answer = 0; 25 | // ❻ 보드에서 가장 큰 값(최대 정사각형의 한 변의 길이)을 찾습니다. 26 | for (int i = 0; i < row; i++) { 27 | for (int j = 0; j < col; j++) { 28 | answer = Math.max(answer, board[i][j]); 29 | } 30 | } 31 | 32 | // ❼ 최대 정사각형의 넓이를 반환합니다. 33 | return answer * answer; 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /solution/76.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | import java.util.HashSet; 3 | 4 | public class Solution { 5 | 6 | private static final int INF = 20_001; 7 | 8 | public int solution(String[] strs, String t) { 9 | int n = t.length(); // ❶ 타겟 문자열 t의 길이 10 | // ❷ 각 위치에서 필요한 최소 조각수를 저장할 배열(초기값은 INF로 함) 11 | int[] dp = new int[n + 1]; 12 | Arrays.fill(dp, INF); 13 | // ❸ 빈 문자열을 위해 필요한 최소 조각수는 0 14 | dp[0] = 0; 15 | 16 | // ❹ strs 조각들의 길이를 저장한 해시셋 17 | HashSet sizes = new HashSet<>(); 18 | for (String str : strs) { 19 | sizes.add(str.length()); 20 | } 21 | 22 | // ❺ dp[i]부터 dp[n]까지 채우기 위한 반복문 23 | for (int i = 1; i <= n; i++) { 24 | // ❻ 각 str 조각의 문자열 길이에 대하여 25 | for (int size : sizes) { 26 | if (i - size >= 0) { 27 | int idx = i; 28 | String sub = t.substring(idx - size, idx); 29 | // ❼ 이미 구한 해와 strs 조각을 추가해서 문자열을 만들 수 있다면 30 | if (Arrays.asList(strs).contains(sub)) { 31 | // ❽ 해당 위치의 최소 조각수를 갱신 32 | dp[i] = Math.min(dp[i], dp[i - size] + 1); 33 | } 34 | } 35 | } 36 | } 37 | 38 | // ❾ 최소 조각수를 반환 39 | return dp[n] < INF ? dp[n] : -1; 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /solution/77.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.Arrays; 3 | 4 | public class Solution { 5 | 6 | public static void main(String[] args) { 7 | System.out.println(Arrays.toString(solution(123))); 8 | System.out.println(Arrays.toString(solution(350))); 9 | } 10 | 11 | // 이 부분을 변경해서 실행해보세요. 12 | private static int[] solution(int amount) { 13 | // ❶ 화폐 단위를 큰 순서대로 정렬해서 저장 14 | int[] denominations = {100, 50, 10, 1}; 15 | 16 | // ❷ 거스름돈을 담을 리스트 17 | ArrayList change = new ArrayList<>(); 18 | 19 | for (int coin : denominations) { 20 | // ❸ 해당 화폐 단위로 거스름돈을 계속 나눠줌 21 | while (amount >= coin) { 22 | change.add(coin); // ❹ 거스름돈 리스트 업데이트 23 | amount -= coin; // ❺ 정산이 완료된 거스름돈 뺌 24 | } 25 | } 26 | // ❻ 거스름돈 리스트를 배열로 변경하여 반환 27 | return change.stream().mapToInt(Integer::intValue).toArray(); 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /solution/78.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | public class Solution { 4 | 5 | public static void main(String[] args) { 6 | int[][] items1 = {{10, 19}, {7, 10}, {6, 10}}; 7 | System.out.println(solution(items1, 15)); 8 | int[][] items2 = {{10, 60}, {20, 100}, {30, 120}}; 9 | System.out.println(solution(items2, 50)); 10 | } 11 | 12 | private static class Item { 13 | int value, weight; 14 | double valuePerWeight; 15 | 16 | public Item(int value, int weight, double valuePerWeight) { 17 | this.value = value; 18 | this.weight = weight; 19 | this.valuePerWeight = valuePerWeight; 20 | } 21 | } 22 | 23 | // 이 부분을 변경해서 실행해보세요. 24 | private static double solution(int[][] items, int weight_limit) { 25 | // ❶ 각 물건의 단위 무게당 가치를 계산하여 item 배열에 추가 26 | Item[] item = new Item[items.length]; 27 | for (int i = 0; i < items.length; i++) { 28 | item[i] = new Item(items[i][1], items[i][0],(double)items[i][1] / items[i][0]); 29 | } 30 | 31 | // ❷ 단위 무게당 가치가 높은 순으로 물건을 정렬 32 | Arrays.sort(item, (o1, o2) -> Double.compare(o2.valuePerWeight, o1.valuePerWeight)); 33 | 34 | double totalValue = 0; // ❸ 선택한 물건들의 총 가치를 저장하는 변수 35 | int remainingWeight = weight_limit; // ❹ 남은 무게 한도를 저장하는 변수 36 | 37 | // ❺ 물건을 선택합니다. 38 | for (Item i : item) { 39 | if (i.weight <= remainingWeight) { 40 | // ❻ 남은 무게 한도 내에서 물건을 통째로 선택 41 | totalValue += i.value; 42 | remainingWeight -= i.weight; 43 | } 44 | else { 45 | // ❼ 남은 무게 한도가 물건의 무게보다 작으면 쪼개서 일부분만 선택 46 | double fraction = (double) remainingWeight / i.weight; 47 | totalValue += i.value * fraction; 48 | break; // ❽ 이미 배낭의 무게 한도를 모두 사용한 경우 49 | } 50 | } 51 | 52 | return totalValue; 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /solution/79.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | public class Solution { 4 | 5 | public int solution(int[] d, int budget) { 6 | Arrays.sort(d); // ❶ 배열 d를 오름차순으로 정렬 7 | int count = 0; // ❷ 지원할 수 있는 부서의 개수를 세는 변수 8 | 9 | for (int amount : d) { 10 | if (budget < amount) { 11 | break; // ❸ 남은 예산이 신청한 금액보다 작으면 더 이상 지원할 수 없으므로 종료 12 | } 13 | budget -= amount; // ❹ 예산에서 신청한 금액을 차감 14 | count++; 15 | } 16 | 17 | return budget >= 0 ? count : count - 1; 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /solution/80.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | public class Solution { 4 | 5 | public int solution(int[] people, int limit) { 6 | Arrays.sort(people); // ❶ 몸무게를 오름차순으로 정렬 7 | int count = 0; // ❷ 필요한 보트 개수 8 | int i = 0; // ❸ 가장 가벼운 사람을 가리키는 인덱스 9 | int j = people.length - 1; // ❹ 가장 무거운 사람을 가르키는 인덱스 10 | 11 | 12 | while (i <= j) { 13 | // ❺ 가장 무거운 사람과 가장 가벼운 사람을 같이 태울 수 있으면 두 사람 모두 보트에 태움 14 | if (people[i] + people[j] <= limit) { 15 | i += 1; 16 | } 17 | // ❻ 무거운 사람만 태울 수 있으면 무거운 사람만 보트에 태움 18 | j -= 1; 19 | count += 1; 20 | } 21 | 22 | return count; 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /solution/81.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.Collections; 3 | import java.util.HashMap; 4 | 5 | public class Solution { 6 | 7 | public int solution(int k, int[] tangerine) { 8 | // ❶ 귤의 개수를 세는 HashMap 객체 생성 9 | HashMap map = new HashMap<>(); 10 | for (int i : tangerine) { 11 | map.put(i, map.getOrDefault(i, 0) + 1); 12 | } 13 | 14 | // ❷ 개수를 내림차순으로 정렬 15 | ArrayList sortedCounts = new ArrayList<>(map.values()); 16 | sortedCounts.sort(Collections.reverseOrder()); 17 | 18 | int numTypes = 0; // ❸ 현재까지의 종류 수 19 | int countSum = 0; // ❹ 현재까지의 귤 개수 합 20 | 21 | for (int count : sortedCounts) { 22 | countSum += count; 23 | numTypes++; 24 | 25 | // ❺ 귤 개수 합이 k 이상이 되는 순간 종료 26 | if (countSum >= k) 27 | break; 28 | } 29 | 30 | return numTypes; 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /solution/82.java: -------------------------------------------------------------------------------- 1 | public class Solution { 2 | 3 | public int solution(int n, int[] stations, int w) { 4 | int answer = 0; 5 | int location = 1; // ❶ 현재 탐색하는 아파트의 위치 6 | int idx = 0; // ❷ 설치된 기지국의 인덱스 7 | 8 | while (location <= n) { 9 | // ❸ 기지국이 설치된 위치에 도달한 경우 10 | if (idx < stations.length && location >= stations[idx] - w) { 11 | location = stations[idx] + w + 1; 12 | idx++; 13 | } 14 | // ❹ 기지국이 설치되지 않은 위치인 경우 15 | else { 16 | location += 2 * w + 1; // ❺ 기지국을 설치하고 해당 범위를 넘어감 17 | answer++; 18 | } 19 | } 20 | 21 | return answer; 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /solution/83.java: -------------------------------------------------------------------------------- 1 | public class Solution { 2 | 3 | public static void main(String[] args) { 4 | System.out.println(solution(3,4,2,3,3 ,1,5)); 5 | System.out.println(solution(2,2,1,1,2 ,2,2)); 6 | System.out.println(solution(3,3,1,2,3 ,3,4)); 7 | } 8 | 9 | public static String solution(int n, int m, int x, int y, int r, int c, int k) { 10 | StringBuilder sb = new StringBuilder(); 11 | 12 | int dist = k - (Math.abs(x - r) + Math.abs(y - c)); 13 | 14 | if (dist < 0 || dist % 2 == 1) { 15 | return "impossible"; 16 | } 17 | 18 | while (k-- > 0) { 19 | int[] next = getNext(n, m, x, y, r, c, k); 20 | x = x + next[0]; 21 | y = y + next[1]; 22 | sb.append((char)next[2]); 23 | } 24 | 25 | return sb.toString(); 26 | } 27 | 28 | // 아래 > 왼쪽 > 오른쪽 > 위쪽 29 | private static int[] getNext(int n, int m, int x, int y, int r, int c, int k) { 30 | if (x + 1 <= n && Math.abs(x + 1 - r) + Math.abs(y - c) <= k) { 31 | return new int[]{1, 0, 'd'}; 32 | } 33 | else if (y - 1 >= 1 && Math.abs(x - r) + Math.abs(y - 1 - c) <= k) { 34 | return new int[]{0, -1, 'l'}; 35 | } 36 | else if (y + 1 <= m && Math.abs(x - r) + Math.abs(y + 1 - c) <= k) { 37 | return new int[]{0, 1, 'r'}; 38 | } 39 | else { 40 | return new int[]{-1, 0, 'u'}; 41 | } 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /solution/84.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | 3 | public static void main(String[] args) { 4 | System.out.println(solution(4, 1, new int[]{0}, new int[]{0})); 5 | } 6 | 7 | public static long solution(int cap, int n, int[] deliveries, int[] pickups) { 8 | int deliveries_idx = n - 1; 9 | int pickups_idx = n - 1; 10 | 11 | while (deliveries_idx >= 0 && deliveries[deliveries_idx] == 0) { 12 | deliveries_idx--; 13 | } 14 | while (pickups_idx >= 0 && pickups[pickups_idx] == 0) { 15 | pickups_idx--; 16 | } 17 | 18 | long answer = 0; 19 | 20 | while (deliveries_idx >= 0 || pickups_idx >= 0) { 21 | answer += (Math.max(deliveries_idx, pickups_idx) + 1) * 2L; 22 | deliveries_idx = getMaxIdx(cap, deliveries, deliveries_idx); 23 | pickups_idx = getMaxIdx(cap, pickups, pickups_idx); 24 | } 25 | 26 | return answer; 27 | } 28 | 29 | private static int getMaxIdx(int cap, int[] target, int idx) { 30 | while (idx >= 0 && (cap > 0 || target[idx] == 0)) { 31 | if (target[idx] > cap) { 32 | target[idx] -= cap; 33 | cap = 0; 34 | } 35 | else { 36 | cap -= target[idx]; 37 | target[idx] = 0; 38 | idx--; 39 | } 40 | } 41 | return idx; 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /solution/85.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.HashMap; 3 | import java.util.StringTokenizer; 4 | 5 | class Solution { 6 | 7 | private static final int MONTH_OF_YEAR = 12; 8 | private static final int DAY_OF_MONTH = 28; 9 | 10 | public int[] solution(String today, String[] terms, String[] privacies) { 11 | int todayDay = stringToDay(today); 12 | 13 | HashMap term = new HashMap<>(); 14 | for (String s : terms) { 15 | StringTokenizer st = new StringTokenizer(s); 16 | term.put(st.nextToken().charAt(0), Integer.parseInt(st.nextToken()) * DAY_OF_MONTH); 17 | } 18 | 19 | ArrayList answer = new ArrayList<>(); 20 | 21 | for (int i = 1; i <= privacies.length; i++) { 22 | StringTokenizer st = new StringTokenizer(privacies[i - 1]); 23 | int day = stringToDay(st.nextToken()) + term.get(st.nextToken().charAt(0)); 24 | if (todayDay >= day) { 25 | answer.add(i); 26 | } 27 | } 28 | 29 | return answer.stream().mapToInt(i -> i).toArray(); 30 | } 31 | 32 | private static int stringToDay(String s) { 33 | StringTokenizer st = new StringTokenizer(s, "."); 34 | int month = (Integer.parseInt(st.nextToken()) - 2000) * MONTH_OF_YEAR + Integer.parseInt(st.nextToken()) - 1; 35 | int day = Integer.parseInt(st.nextToken()); 36 | return month * DAY_OF_MONTH + day; 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /solution/86.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayDeque; 2 | import java.util.Arrays; 3 | 4 | class Solution { 5 | 6 | public static void main(String[] args) { 7 | System.out.println(Arrays.toString(solution(new String[]{"1110","100111100","0111111010"}))); 8 | System.out.println(Arrays.toString(solution(new String[]{"1011110","01110","101101111010"}))); 9 | System.out.println(Arrays.toString(solution(new String[]{"1100111011101001"}))); 10 | } 11 | 12 | public static String[] solution(String[] s) { 13 | String[] answer = new String[s.length]; 14 | 15 | for (int i = 0; i < s.length; i++) { 16 | StringBuilder start = new StringBuilder(); 17 | ArrayDeque stack = new ArrayDeque<>(); 18 | char[] end = s[i].toCharArray(); 19 | 20 | for (char c : end) { 21 | stack.push(c); 22 | if (stack.size() >= 3) { 23 | char s3 = stack.pop(); 24 | char s2 = stack.pop(); 25 | char s1 = stack.pop(); 26 | if (("" + s1 + s2 + s3).equals("110")) { 27 | start.append("110"); 28 | } 29 | else { 30 | stack.push(s1); 31 | stack.push(s2); 32 | stack.push(s3); 33 | } 34 | } 35 | } 36 | 37 | StringBuilder ans = new StringBuilder(); 38 | while (!stack.isEmpty()) { 39 | ans.append(stack.pollLast()); 40 | } 41 | 42 | if (ans.indexOf("11") >= 0) { 43 | ans.insert(ans.indexOf("11"), start); 44 | } 45 | else if (ans.lastIndexOf("0") >= 0) { 46 | ans.insert(ans.lastIndexOf("0") + 1, start); 47 | } 48 | else { 49 | ans.insert(0, start); 50 | } 51 | 52 | answer[i] = ans.toString(); 53 | } 54 | 55 | return answer; 56 | } 57 | 58 | } -------------------------------------------------------------------------------- /solution/87.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | class Solution { 4 | 5 | public static void main(String[] args) { 6 | int[][] a1 = {{1, 1, 0, 0}, {1, 0, 0, 0}, {1, 0, 0, 1}, {1, 1, 1, 1}}; 7 | System.out.println(Arrays.toString(solution(a1))); 8 | int[][] a2 = {{1, 1, 1, 1, 1, 1, 1, 1}, {0, 1, 1, 1, 1, 1, 1, 1}, {0, 0, 0, 0, 1, 1, 1, 1}, {0, 1, 0, 0, 1, 1, 1, 1}, {0, 0, 0, 0, 0, 0, 1, 1}, {0, 0, 0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 1, 0, 0, 1}, {0, 0, 0, 0, 1, 1, 1, 1}}; 9 | System.out.println(Arrays.toString(solution(a2))); 10 | } 11 | 12 | public static int[] solution(int[][] arr) { 13 | int[][] rev = new int[arr.length][arr.length]; 14 | for (int i = 0; i < rev.length; i++) { 15 | rev[i] = arr[i].clone(); 16 | for (int j = 0; j < rev.length; j++) { 17 | rev[i][j] ^= 1; 18 | } 19 | } 20 | 21 | Compression(arr); 22 | int one = sum(arr); 23 | Compression(rev); 24 | int zero = sum(rev); 25 | 26 | return new int[]{zero, one}; 27 | } 28 | 29 | private static void Compression(int[][] arr) { 30 | for (int p = 0; Math.pow(2, p) < arr.length; p++) { 31 | int pow = (int)Math.pow(2, p); 32 | int quad = (int)Math.pow(4, p + 1); 33 | for (int i = (pow * 2) - 1; i < arr.length; i += (pow * 2)) { 34 | for (int j = (pow * 2) - 1; j < arr.length; j += (pow * 2)) { 35 | if (arr[i][j] + arr[i - pow][j] + arr[i][j - pow] + arr[i - pow][j - pow] == quad) { 36 | arr[i - pow][j] = arr[i][j - pow] = arr[i - pow][j - pow] = 0; 37 | arr[i][j] = quad; 38 | } 39 | } 40 | } 41 | } 42 | } 43 | 44 | private static int sum(int[][] arr) { 45 | int sum = 0; 46 | for (int[] a : arr) { 47 | for (int x : a) { 48 | if (x > 0) 49 | sum++; 50 | } 51 | } 52 | return sum; 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /solution/88.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public int solution(int[] numbers) { 3 | int answer = 45; 4 | for (int n : numbers) 5 | answer -= n; 6 | return answer; 7 | } 8 | } -------------------------------------------------------------------------------- /solution/89.java: -------------------------------------------------------------------------------- 1 | import java.util.HashSet; 2 | import java.util.regex.Pattern; 3 | 4 | class Solution { 5 | 6 | public static void main(String[] args) { 7 | String[] user_id_3 = {"frodo", "fradi", "crodo", "abc123", "frodoc"}; 8 | String[] banned_id_3 = {"fr*d*", "*rodo", "******", "******"}; 9 | System.out.println(solution(user_id_3, banned_id_3)); 10 | } 11 | 12 | public static int solution(String[] user_id, String[] banned_id) { 13 | answer = new HashSet<>(); 14 | userId = user_id; 15 | used = new boolean[banned_id.length]; 16 | regex = new Pattern[banned_id.length]; 17 | 18 | for (int i = 0; i < banned_id.length; i++) { 19 | regex[i] = Pattern.compile(banned_id[i].replace("*", "[a-z0-9]")); 20 | } 21 | 22 | backtrack(0, ""); 23 | 24 | return answer.size(); 25 | } 26 | 27 | private static String[] userId; 28 | private static Pattern[] regex; 29 | private static boolean[] used; 30 | private static HashSet answer; 31 | 32 | private static void backtrack(int idx, String users) { 33 | if (users.length() == regex.length) { 34 | answer.add(users); 35 | } 36 | 37 | for (int i = idx; i < userId.length; i++) { 38 | String id = userId[i]; 39 | for (int j = 0; j < regex.length; j++) { 40 | if (!used[j] && regex[j].matcher(id).matches()) { 41 | used[j] = true; 42 | backtrack(i + 1, users + i); 43 | used[j] = false; 44 | } 45 | } 46 | } 47 | } 48 | 49 | } -------------------------------------------------------------------------------- /solution/90.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | 3 | public static void main(String[] args) { 4 | System.out.println(solution(437674, 3)); 5 | System.out.println(solution(110011, 2)); 6 | } 7 | 8 | public static int solution(int n, int k) { 9 | String[] p = Integer.toString(n, k).split("0"); 10 | int answer = 0; 11 | for (String s : p) { 12 | if(!s.isEmpty() && isPrimeNumber(Long.parseLong(s))) 13 | answer++; 14 | } 15 | return answer; 16 | } 17 | 18 | private static boolean isPrimeNumber(long num) { 19 | if (num == 1) return false; 20 | boolean isPrime = true; 21 | int sqrt = (int)Math.sqrt(num + 1); 22 | 23 | for(int i = 2; i <= sqrt; i++) { 24 | if(num % i == 0) { 25 | isPrime = false; 26 | break; 27 | } 28 | } 29 | 30 | return isPrime; 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /solution/91.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | 3 | private static int[] dx = {0, 0, 1, -1}; 4 | private static int[] dy = {1, -1, 0, 0}; 5 | 6 | public int[] solution(String[][] places) { 7 | int[] answer = {1, 1, 1, 1, 1}; 8 | 9 | for (int t = 0; t < places.length; t++) { 10 | char[][] place = new char[5][5]; 11 | for (int i = 0; i < 5; i++) { 12 | place[i] = places[t][i].toCharArray(); 13 | } 14 | 15 | for (int i = 0; i < 5; i++) { 16 | for (int j = 0; j < 5; j++) { 17 | if (place[i][j] == 'P') { 18 | for (int k = 0; k < 4; k++) { 19 | int x = i + dx[k]; 20 | int y = j + dy[k]; 21 | 22 | if (x < 0 || x > 4 || y < 0 || y > 4) 23 | continue; 24 | 25 | if (place[x][y] == 'P' || place[x][y] == 'p') 26 | answer[t] = 0; 27 | 28 | if (place[x][y] == 'O') 29 | place[x][y] = 'p'; 30 | } 31 | } 32 | } 33 | } 34 | 35 | } 36 | 37 | return answer; 38 | } 39 | } -------------------------------------------------------------------------------- /solution/92.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | 3 | public static void main(String[] args) { 4 | System.out.println(solution(10, 10, new int[][]{{10,15,2,1,2},{20,20,3,3,4}})); 5 | } 6 | 7 | public static int solution(int alp, int cop, int[][] problems) { 8 | int maxAlp = 0; 9 | int maxCop = 0; 10 | 11 | for (int[] problem : problems) { 12 | maxAlp = Math.max(maxAlp, problem[0]); 13 | maxCop = Math.max(maxCop, problem[1]); 14 | } 15 | 16 | int[][] dp = new int[maxAlp + 2][maxCop + 2]; 17 | 18 | for (int i = 0; i <= maxAlp; i++) { 19 | for (int j = 0; j <= maxCop; j++) { 20 | dp[i][j] = Math.max(i - alp, 0) + Math.max(j - cop, 0); 21 | } 22 | } 23 | 24 | for (int i = 0; i <= maxAlp; i++) { 25 | for (int j = 0; j <= maxCop; j++) { 26 | for (int[] problem : problems) { 27 | if (problem[0] > i || problem[1] > j) 28 | continue; 29 | int x = Math.min(i + problem[2], maxAlp); 30 | int y = Math.min(j + problem[3], maxCop); 31 | dp[x][y] = Math.min(dp[x][y], dp[i][j] + problem[4]); 32 | } 33 | 34 | dp[i + 1][j] = Math.min(dp[i + 1][j], dp[i][j] + 1); 35 | dp[i][j + 1] = Math.min(dp[i][j + 1], dp[i][j] + 1); 36 | } 37 | } 38 | 39 | return dp[maxAlp][maxCop]; 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /solution/93.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayDeque; 2 | 3 | class Solution { 4 | 5 | public int solution(int[] queue1, int[] queue2) { 6 | long sum1 = 0, sum2 = 0; 7 | ArrayDeque queue = new ArrayDeque<>(); 8 | 9 | for (int i : queue1) { 10 | queue.add(i); 11 | sum1 += i; 12 | } 13 | 14 | for (int i : queue2) { 15 | sum2 += i; 16 | } 17 | 18 | long target = (sum1 + sum2) / 2; 19 | 20 | int q2 = 0; 21 | 22 | int count = 0; 23 | 24 | while (!queue.isEmpty() && q2 < queue2.length) { 25 | if (sum1 == target) 26 | break; 27 | 28 | if (sum1 < target) { 29 | queue.add(queue2[q2]); 30 | sum1 += queue2[q2]; 31 | q2++; 32 | } 33 | else { 34 | sum1 -= queue.poll(); 35 | } 36 | 37 | count++; 38 | } 39 | 40 | if (sum1 != target) 41 | return -1; 42 | 43 | return count; 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /solution/94.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | class Solution { 4 | 5 | public int solution(int[] A, int[] B) { 6 | Arrays.sort(A); 7 | Arrays.sort(B); 8 | 9 | int l = B.length - 1; 10 | int answer = 0; 11 | 12 | for (int i = A.length - 1; i >= 0; i--) { 13 | if (A[i] < B[l]) { 14 | l--; 15 | answer++; 16 | } 17 | } 18 | 19 | return answer; 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /solution/95.java: -------------------------------------------------------------------------------- 1 | import java.util.HashMap; 2 | import java.util.Optional; 3 | 4 | class Solution { 5 | 6 | public int[] solution(String[] gems) { 7 | HashMap map = new HashMap<>(); 8 | for (String gem : gems) map.put(gem, 0); 9 | 10 | int l = 0, r = 0, min = gems.length + 1, al = 1, ar = gems.length, max = map.size(); 11 | map = new HashMap<>(); 12 | 13 | while (r < gems.length) { 14 | int cnt = Optional.ofNullable(map.get(gems[r])).orElse(0) + 1; 15 | map.put(gems[r++], cnt); 16 | 17 | while (map.size() == max) { 18 | if (min > r - l) { 19 | min = r - l; 20 | al = l + 1; 21 | ar = r; 22 | } 23 | cnt = map.get(gems[l]) - 1; 24 | if(cnt == 0) map.remove(gems[l]); 25 | else map.put(gems[l], cnt); 26 | l++; 27 | } 28 | } 29 | 30 | return new int[]{al, ar}; 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /solution/96.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | 3 | public static void main(String[] args) { 4 | int[][] board2 = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; 5 | int[][] skill2 = {{1, 1, 1, 2, 2, 4}, {1, 0, 0, 1, 1, 2}, {2, 2, 0, 2, 0, 100}}; 6 | System.out.println(solution(board2, skill2)); 7 | } 8 | 9 | public static int solution(int[][] board, int[][] skill) { 10 | int[][] sum = new int[board.length + 1][board[0].length + 1]; 11 | 12 | for (int[] s : skill) { 13 | int degree = s[5] * (s[0] == 1 ? -1 : 1); 14 | sum[s[1]][s[2]] += degree; 15 | sum[s[3] + 1][s[4] + 1] += degree; 16 | sum[s[1]][s[4] + 1] -= degree; 17 | sum[s[3] + 1][s[2]] -= degree; 18 | } 19 | 20 | for (int i = 0; i < sum.length; i++) { 21 | for (int j = 1; j < sum[0].length; j++) { 22 | sum[i][j] += sum[i][j - 1]; 23 | } 24 | } 25 | 26 | for (int i = 1; i < sum.length; i++) { 27 | for (int j = 0; j < sum[0].length; j++) { 28 | sum[i][j] += sum[i - 1][j]; 29 | } 30 | } 31 | 32 | int answer = 0; 33 | 34 | for (int i = 0; i < board.length; i++) { 35 | for (int j = 0; j < board[0].length; j++) { 36 | if (board[i][j] + sum[i][j] > 0) 37 | answer++; 38 | } 39 | } 40 | 41 | return answer; 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /solution/97.java: -------------------------------------------------------------------------------- 1 | import java.util.HashSet; 2 | 3 | class Solution { 4 | public int[] solution(int[] lottos, int[] win_nums) { 5 | HashSet win = new HashSet<>(); 6 | for (int winNum : win_nums) { 7 | win.add(winNum); 8 | } 9 | 10 | int zero = 0, match = 0; 11 | 12 | for (int lotto : lottos) { 13 | if (lotto == 0) zero++; 14 | else if (win.contains(lotto)) match++; 15 | } 16 | 17 | return new int[]{7 - Math.max((match + zero), 1), 7 - Math.max(match, 1)}; 18 | } 19 | } --------------------------------------------------------------------------------