diff --git a/dohun/week6/ProgrammersDoublePriorityQueue.java b/dohun/week6/ProgrammersDoublePriorityQueue.java new file mode 100644 index 0000000..5a78073 --- /dev/null +++ b/dohun/week6/ProgrammersDoublePriorityQueue.java @@ -0,0 +1,46 @@ +import java.util.*; + +class Solution { + public int[] solution(String[] operations) { + // 최소 힙과 최대 힙 생성 + PriorityQueue minHeap = new PriorityQueue<>(); + PriorityQueue maxHeap = new PriorityQueue<>(Collections.reverseOrder()); + + // 명령어 처리 + for (String command : operations) { + String[] temp = command.split(" "); + if (temp[0].equals("I")) { + // 삽입은 두 힙에 모두 삽입 + minHeap.add(Integer.parseInt(temp[1])); + maxHeap.add(Integer.parseInt(temp[1])); + } else if (temp[1].equals("1")) { + // 최대값 삭제 + if (!minHeap.isEmpty()) { + // 최대 힙에서 꺼낸 값을 최소 힙에서도 삭제 + minHeap.remove(maxHeap.poll()); + } + } else { + // 최소값 삭제 + if (!maxHeap.isEmpty()) { + // 최소 힙에서 꺼낸 값을 최대 힙에서도 삭제 + maxHeap.remove(minHeap.poll()); + } + } + } + // 결과 반환 + int[] answer = new int[2]; + // 힙이 비어있는 경우 + if (minHeap.isEmpty()) { + answer[0] = 0; + answer[1] = 0; + } else if (minHeap.size() == 1) { // 원소가 하나 남아있는 경우 + int temp = minHeap.poll(); + answer[0] = temp; + answer[1] = temp; + } else { // 원소가 두 개 이상 남아있는 경우 + answer[0] = maxHeap.poll(); + answer[1] = minHeap.poll(); + } + return answer; + } +} diff --git a/dohun/week6/ProgrammersEnglishWordChain.java b/dohun/week6/ProgrammersEnglishWordChain.java new file mode 100644 index 0000000..e523580 --- /dev/null +++ b/dohun/week6/ProgrammersEnglishWordChain.java @@ -0,0 +1,35 @@ +import java.util.*; + +class ProgrammersEnglishWordChain { + public int[] solution(int n, String[] words) { + Set usedWords = new HashSet<>(); + + // 첫 번째 단어 추가 + usedWords.add(words[0]); + + for(int i = 1; i < words.length; i++) { + // 현재 단어와 이전 단어 가져오기 + String currentWord = words[i]; + String previousWord = words[i - 1]; + + // (i % n) + 1 -> 몇 번째 사람인가 + // (i / n) + 1 -> 몇 번째 차례인가 + + // 규칙 1 : 이미 말한 단어일때 + if(usedWords.contains(currentWord)) { + return new int[] { (i % n) + 1, (i / n) + 1 }; + } + + // 규칙 2 : 앞 글자가 이전 단어의 뒷 글자와 다를때 + if(currentWord.charAt(0) != previousWord.charAt(previousWord.length() - 1)) { + return new int[] { (i % n) + 1, (i / n) + 1 }; + } + + // 사용한 단어에 현재 단어 추가 + usedWords.add(currentWord); + } + + // 탈락자 없이 끝난 경우 + return new int[] {0, 0}; + } +} diff --git a/dohun/week6/ProgrammersSheepAndWolf.java b/dohun/week6/ProgrammersSheepAndWolf.java new file mode 100644 index 0000000..0446758 --- /dev/null +++ b/dohun/week6/ProgrammersSheepAndWolf.java @@ -0,0 +1,89 @@ +import java.util.*; + +class ProgrammersSheepAndWolf { + // 트리 구조를 저장할 인접 리스트 + List[] tree; + + // 각 노드에 있는 동물 정보 (0 = 양, 1 = 늑대) + int[] info; + + // 최대로 모을 수 있는 양의 수 (DFS 과정에서 계속 갱신) + int answer = 0; + + public int solution(int[] info, int[][] edges) { + this.info = info; + int n = info.length; + + // 트리 초기화 (각 노드의 자식 리스트 생성) + tree = new ArrayList[n]; + for(int i = 0; i < n; i++) { + tree[i] = new ArrayList<>(); + } + + // 부모 → 자식 간선 연결 + for(int[] e : edges) { + tree[e[0]].add(e[1]); + } + + // 방문 가능한 노드 목록 (처음에는 루트(0)만 가능) + List next = new ArrayList<>(); + next.add(0); + + // DFS 시작: 현재 양=0, 늑대=0, 방문 가능한 노드= {0} + dfs(0, 0, next); + + return answer; + } + + + // DFS 탐색 함수 + // sheep 현재까지 모은 양 수 + // wolf 현재까지 만난 늑대 수 + // possible 현재 상태에서 앞으로 "방문할 수 있는 모든 노드" + void dfs(int sheep, int wolf, List possible) { + + // 매 탐색마다 현재까지 모은 양의 수로 최대값을 갱신 + answer = Math.max(answer, sheep); + + // 현재 방문 가능한 모든 노드를 하나씩 선택해 이동해 본다 + for(int i = 0; i < possible.size(); i++) { + + int node = possible.get(i); // 이번에 방문할 노드 + + int newSheep = sheep; + int newWolf = wolf; + + // 선택한 노드의 동물 종류에 따라 양 또는 늑대 증가 + if(info[node] == 0) { + newSheep++; // 양 + } else { + newWolf++; // 늑대 + } + + // 규칙: 늑대가 양 이상이면 양이 모두 잡아먹혀서 해당 경로는 중단 + if(newWolf >= newSheep) { + continue; + } + + // 새로운 possible 리스트 만들기 + // 현재 방문한 노드를 제외하고 그 노드의 자식들을 추가 + // 새 리스트가 필요한 이유 + // DFS 특성상 각 분기마다 possible 목록이 달라야 하기 때문 + // 하나의 리스트를 공용으로 쓰면 다른 경로 탐색에 영향을 끼침 + List newPossible = new ArrayList<>(possible); + newPossible.remove(i); // 이번에 방문한 노드는 제거 + + // 방문한 노드의 자식들은 앞으로 방문 가능한 후보가 됨 + for(int child : tree[node]) { + newPossible.add(child); + } + + // DFS 재귀 호출 + // 상태를 업데이트한 뒤 다음 가능한 모든 노드들로 다시 탐색 + // 여기서 중요한 점: + // 현재 노드의 자식뿐만 아니라 기존에 방문하지 않은 다른 후보도 계속 남아있음 + // 즉 트리를 직선으로 탐색하는 것이 아니라 '방문 가능한 상태 집합'을 들고 다니는 DFS라고 생각하면 됨 + dfs(newSheep, newWolf, newPossible); + } + } +}