프로그래머스 코딩테스트 고득점 Kit 47문제 Java 풀이

프로그래머스 코딩테스트 고득점 Kit 47문제

https://school.programmers.co.kr/learn/challenges?tab=algorithm_practice_kit
LV.1 ~ LV.3 43문제를 순서대로 익히고, 취업 시즌에 문법 복습 후 시간 제한을 두고 다시 풀어보면 좋습니다.

난이도 낮은 순서
정렬, 스택/큐, 완전탐색 > 힙, 해시, 깊이/너비 우선 탐색(DFS/BFS), 탐욕법(Greedy) > 동적계획법(DP), 이분탐색, 그래프
코테 준비 기간이 여유롭다면, 쉬운 유형부터 천천히 풀어나가는 것이 좋습니다.

출제 빈도 높은 순서
깊이/너비 우선 탐색(DFS/BFS), 완전탐색, 정렬, 해시 > 스택/큐, 힙 > 동적계획법(DP), 그래프, 탐욕법(Greedy), 이분탐색
코테를 준비할 시간이 없다면, 가장 출제 빈도가 높은 DFS/BFS를 우선 공부해야 합니다.

해시 문제 풀이

LV.1 폰켓몬

import java.util.HashSet;

class Solution {
  public int solution(int[] nums) {

    HashSet<Integer> hs = new HashSet<>();

    for(int i =0; i<nums.length;i++) {
      hs.add(nums[i]);
    }

    if(hs.size()>nums.length/2)
      return nums.length/2;

    return hs.size();
  }
}

HashSet은 중복된 요소를 없애줍니다.

LV.1 완주하지 못한 선수

import java.util.HashMap;

public class Solution {
  public String solution(String[] participant, String[] completion) {
    // 해시맵 생성
    HashMap<String, Integer> hashMap = new HashMap<>();
    
    // 완주한 선수들의 이름을 해시맵에 저장
    for (String string : completion) {
      hashMap.put(string, hashMap.getOrDefault(string, 0) + 1);
    }

    // 참가한 선수들의 이름을 키로 하는 값을 1씩 감소
    for (String string : participant) {
      // 완주하지 못한 선수를 찾으면 반환
      if (hashMap.getOrDefault(string, 0) == 0) {
        return string;
      }
      hashMap.put(string, hashMap.get(string) - 1);
    }

    return null;
  }
}

LV.2 전화번호 목록

import java.util.Arrays;

public class Solution {
  public boolean solution(String[] phone_book) {
    // 전화번호부 정렬
    Arrays.sort(phone_book);

    // 전화번호부에서 연속된 두 개의 전화번호 비교
    for (int i = 0; i < phone_book.length - 1; i++) {
      if (phone_book[i + 1].startsWith(phone_book[i]))
        return false;
    }

    // 모든 전화번호를 비교한 후에도 반환되지 않았다면, 접두어가 없는 경우이므로 true 반환
    return true;
  }
}
import java.util.HashMap;

class Solution {
  public boolean solution(String[] phoneBook) {
    boolean answer = true;

    HashMap<String, Integer> map = new HashMap<>();

    for(int i = 0; i < phoneBook.length; i++) {
      map.put(phoneBook[i], i);
    }

    for(int i = 0; i < phoneBook.length; i++) {
      for(int j = 0; j < phoneBook[i].length(); j++) {
        if(map.containsKey(phoneBook[i].substring(0,j))) {
          answer = false;
          return answer;
        }
      }
    }

    return answer;
  }
}

LV.2 의상

import java.util.HashMap;
import java.util.Iterator;

class Solution {
  public int solution(String[][] clothes) {
    int answer = 1;
    HashMap<String, Integer> map = new HashMap<>();
    
    for(int i = 0; i < clothes.length; i++){
      String key = clothes[i][1];
      if(!map.containsKey(key)) {
        map.put(key, 1);
      } else {
        map.put(key, map.get(key) + 1);
      }
    }
    
    Iterator<Integer> it = map.values().iterator();
    
    while(it.hasNext()) {
      answer *= it.next().intValue()+1;
    }
    
    return answer-1;
  }
}

LV.3 베스트앨범

import java.util.HashMap;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.Collections;

class Solution {
  public int[] solution(String[] genres, int[] plays) {
    // 장르, 곡 정보
    HashMap<String, Object> genresMap = new HashMap<String, Object>();
    // 장르, 총 장르 재생수
    HashMap<String, Integer> playMap = new HashMap<String, Integer>();
    ArrayList<Integer> resultAL = new ArrayList<Integer>();

    for(int i = 0; i < genres.length; i++){
      String key = genres[i];
      // 곡 정보 : 곡 고유번호, 재생횟수
      HashMap<Integer, Integer> infoMap;

      if(genresMap.containsKey(key)){
        infoMap = (HashMap<Integer, Integer>)genresMap.get(key);
      } else {
        infoMap = new HashMap<Integer, Integer>();
      }

      infoMap.put(i, plays[i]);
      genresMap.put(key, infoMap);

      // 재생수
      if(playMap.containsKey(key)){
        playMap.put(key, playMap.get(key) + plays[i]);
      } else {
        playMap.put(key, plays[i]);
      }
    }

    int mCnt = 0;
    Iterator it = sortByValue(playMap).iterator();

    while(it.hasNext()){
      String key = (String)it.next();
      Iterator indexIt = sortByValue((HashMap<Integer, Integer>)genresMap.get(key)).iterator();
      int playsCnt = 0;

      while(indexIt.hasNext()){
        resultAL.add((int)indexIt.next());
        mCnt++;
        playsCnt++;
        if(playsCnt > 1) break;
      }
    }

    int[] answer = new int[resultAL.size()];

    for(int i = 0; i < resultAL.size(); i++){
      answer[i] = resultAL.get(i).intValue();
    }

    return answer;
  }

  private ArrayList sortByValue(final Map map){
    ArrayList<Object> keyList = new ArrayList();
    keyList.addAll(map.keySet());

    Collections.sort(keyList, new Comparator(){
      public int compare(Object o1, Object o2){
        Object v1 = map.get(o1);
        Object v2 = map.get(o2);

        return ((Comparable) v2).compareTo(v1);
      }
    });

    return keyList;
  }
}

스택/큐 문제 풀이

LV.1 같은 숫자는 싫어

import java.util.*;

public class Solution {
  public int[] solution(int []arr) {
    ArrayList<Integer> list = new ArrayList<Integer>();
    
    // 초기값 추가
    list.add(arr[0]);
    
    // 가변형 ArrayList에 연속 중복 제거하여 추가
    for (int i = 1; i < arr.length; i++) {
      if (arr[i] != arr[i-1]) {
        list.add(arr[i]);
      }
    }
    
    // ArrayList를 int 배열로 변경하여 반환
    int[] intArr = new int[list.size()];
    
    for (int i = 0; i < list.size(); i++) {
      intArr[i] = list.get(i);
    }

    return intArr;
  }
}

LV.2 기능개발

import java.util.*;

class Solution {
  public int[] solution(int[] progresses, int[] speeds) {
    // 각 작업의 남은 작업일수를 담기 위한 큐 선언
    Queue<Integer> q = new ArrayDeque<>();
    List<Integer> answerList = new ArrayList<>();

    for (int i = 0; i < speeds.length; i++) {
      // 현재 작업의 남은 작업일수 계산
      // 정수 나눗셈이 아닌, 부동소수점 연산을 하도록 둘 중 하나 (double) 형변환
      double remain = ((double) 100 - progresses[i]) / speeds[i];
      int date = (int) Math.ceil(remain);
        
      // 큐가 비어있지 않고, 큐 첫번째 작업의 남은 일수보다 현재 작업의 남은 일수가 크면
      if (!q.isEmpty() && q.peek() < date) {
        // 정답 리스트에 큐에 쌓인 작업 수 추가 후 큐 초기화
        answerList.add(q.size());
        q.clear();
      }

      // 큐에 현재 작업의 남은 작업일수 추가
      q.offer(date);
    }

    // 마지막으로 큐에 남은 작업 수 추가
    answerList.add(q.size());

    // ArrayList를 int 배열로 변환하여 리턴
    int[] answer = new int[answerList.size()];

    for (int i = 0; i < answer.length; i++) {
      answer[i] = answerList.get(i);
    }

    return answer;
  }
}

LV.2 올바른 괄호

import java.util.*;

class Solution {
  boolean solution(String s) {
    Deque<Character> stack = new ArrayDeque<>();
    
    for (char c : s.toCharArray()) {
      if (c == '(') {
        // 괄호 열기 시 스택에 추가
        stack.push(c);

      } else {
        if (stack.isEmpty()) {
            return false;
        }
        
        // 올바른 괄호이면 스택에서 꺼내기
        stack.pop();
      }
    }
    
    // 반복문 종료 후 스택이 비어있지 않으면 올바르지 않은 괄호
    return stack.isEmpty();
  }
}
class Solution {
  boolean solution(String s) {
    boolean answer = false;
    int count = 0;
    
    for (int i = 0; i < s.length(); i++) {
        if (s.charAt(i) == '(') {
          // 현재 문자열이 괄호 열기면 +1
          count++;
        } else {
          // 현재 문자열이 괄호 닫기면 -1
          count--;
        }
        
        // 괄호 닫기가 더 많은 경우
        if (count < 0) {
          break;
        }
    }
    
    // 괄호 열기, 닫기 횟수가 짝이 맞으면 true
    if (count == 0) {
      answer = true;
    }

    return answer;
  }
}

LV.2 프로세스

import java.util.*;

class Solution {
  public int solution(int[] priorities, int location) {
    int answer = 1;
    
    // 숫자가 클수록 우선순위가 높으므로, 내림차순 정렬 세팅
    PriorityQueue<Integer> pq = new PriorityQueue<>(Collections.reverseOrder());
    
    // 우선순위 큐에 원소 삽입
    for (int v : priorities) {
      pq.add(v);
    }
    
    // 큐가 비어있을 때까지 반복
    while (!pq.isEmpty()) {
      // 현재 우선순위 원소 인덱스 확인
      for (int i = 0; i < priorities.length; i++) {
        if (pq.peek() == priorities[i]) {
          // location과 같으면 현재 순번 반환
          if (i == location) {
            return answer;
          }
          
          // 큐에서 원소 꺼내기
          pq.poll();
          answer++;
        }
      }
    }
    
    return answer;
  }
}

LV.2 다리를 지나는 트럭
트럭은 1초에 1칸씩 전진할 수 있다고 가정하고 풀어야 합니다.

import java.util.*;

class Solution {
  // 트럭 객체 생성
  class Truck {
    int weight;
    int move;
    
    public Truck(int weight) {
      this.weight = weight;
      this.move = 1;
    }
    
    public void moving() {
      move++;
    }
  }
  
  public int solution(int bridge_length, int weight, int[] truck_weights) {
    int answer = 0;
    int cur_weight = 0;
    
    Queue<Truck> waitQ = new ArrayDeque<>();
    Queue<Truck> moveQ = new ArrayDeque<>();
    
    // 대기 중인 트럭을 대기 트럭 큐에 추가
    for (int t_w : truck_weights) {
      waitQ.offer(new Truck(t_w));
    }
    
    // 대기 트럭 큐, 다리를 건너는 트럭 큐 모두 비어있지 않을 때까지 반복
    while (!waitQ.isEmpty() || !moveQ.isEmpty()) {
      // 반복할 때마다 1초 경과
      answer++;
      
      // 다리를 건너는 트럭이 없으면
      if (moveQ.isEmpty()) {
        // 대기 중인 트럭을 꺼내서 다리에 올림
        Truck t = waitQ.poll();
        cur_weight += t.weight;
        moveQ.offer(t);
        continue;
      }
      
      // 다리를 건너는 트럭들을 한 칸씩 이동시킴
      for (Truck t : moveQ) {
        t.moving();
      }
      
      // 다리를 건너는 첫 번째 트럭이 다리를 다 건넜는지 확인
      if (moveQ.peek().move > bridge_length) {
        // 다리를 다 건넌 트럭을 다리에서 제거하고 현재 다리 위의 무게에서 빼줌
        Truck t = moveQ.poll();
        cur_weight -= t.weight;
      }
      
      // 대기 중인 트럭이 있고, 다음 대기 중인 트럭을 다리에 올려도 다리의 최대 무게를 초과하지 않는 경우
      if (!waitQ.isEmpty() && cur_weight + waitQ.peek().weight <= weight) {
        // 대기 중인 다음 트럭을 꺼내서 다리에 올리고 현재 다리 위의 무게에 더해줌
        Truck t = waitQ.poll();
        cur_weight += t.weight;
        moveQ.offer(t);
      }
    }
    
    return answer;
  }
}

LV.2 주식 가격

class Solution {
  public int[] solution(int[] prices) {
    int[] answer = new int[prices.length];
    
    // i번째와 i+1번째 원소 값 비교
    for (int i = 0; i < prices.length; i++) {
      for (int j = i+1; j < prices.length; j++) {
        // 답안 배열 i번째에 +1
        answer[i]++;
        
        // i번째 원소 값이 더 크면 안쪽 반복문 탈출
        if (prices[i] > prices[j]) {
          break;
        }
      }
    }
    
    return answer;
  }
}
import java.util.Stack;

class Solution {
  public static int[] solution(int[] prices) {
    int n = prices.length;

    // 가격이 떨어지지 않은 기간을 저장할 배열
    int[] answer = new int[n];

    // 스택(stack)을 사용해 이전 가격과 현재 가격 비교
    Stack<Integer> stack = new Stack<>();
    stack.push(0);

    for (int i = 1; i < n; i++) {
      while (!stack.isEmpty() && prices[i] < prices[stack.peek()]) {
        // 가격이 떨어졌으므로 이전 가격의 기간 계산
        int j = stack.pop();
        answer[j] = i - j;
      }
      stack.push(i);
    }

    // 스택에 남아 있는 가격들은 가격이 떨어지지 않은 경우
    while (!stack.isEmpty()) {
      int j = stack.pop();
      answer[j] = n - 1 - j;
    }

    return answer;
  }
}

힙(Heap) 문제 풀이

LV.2 더 맵게

import java.util.*;

class Solution {
  public int solution(int[] scoville, int K) {
    int answer = 0;
        
    PriorityQueue<Integer> pq = new PriorityQueue<>();
    
    for (int i = 0; i < scoville.length; i++) {
      pq.offer(scoville[i]);
    }
    
    while (pq.size() >= 2) {
      int poodScoville = pq.poll();
      
      if (poodScoville >= K) {
        break;
      }
      
      pq.offer(poodScoville + (pq.poll() * 2));
      
      answer++;
    }
    
    if (pq.peek() < K) {
      answer = -1;
    }
    
    return answer;
  }
}

힙(완전이진트리)을 이용해서 우선순위 큐를 구현할 수 있습니다.
위보다 아래 코드가 간결하지만 동일하게 동작합니다.

import java.util.*;

class Solution {
  public int solution(int[] scoville, int K) {
    int answer = 0;
        
    PriorityQueue<Integer> pq = new PriorityQueue<>();
    
    for (int v : scoville) {
      pq.offer(v);
    }
    
    while (pq.size() >= 2 && pq.peek() < K) {
      int poodScoville = pq.poll();
      
      pq.offer(poodScoville + (pq.poll() * 2));
      
      answer++;
    }
    
    if (pq.peek() < K) {
      answer = -1;
    }
    
    return answer;
  }
}

LV.3 디스크 컨트롤러

import java.util.Arrays;
import java.util.PriorityQueue;

class Solution {
  public int solution(int[][] jobs) {
    int answer = 0;

    // 작업이 요청되는 시점 기준으로 오름차순 정렬
    Arrays.sort(jobs, (o1, o2) -> o1[0] - o2[0]);

    // 작업의 소요시간 기준으로 오름차순 정렬
    PriorityQueue<int[]> pq = new PriorityQueue<>((o1, o2) -> o1[1] - o2[1]);

    int jobs_index = 0; // 작업 배열 인덱스
    int finish_job = 0; // 처리 완료된 작업 개수
    int end_time = 0; // 작업 처리 완료 시간

    while(true) {
      if(finish_job == jobs.length) break; // 모든 작업을 처리했다면 종료

      // 이전 작업 처리 중 요청된 작업 add
      while(jobs_index < jobs.length && jobs[jobs_index][0] <= end_time) {
        pq.add(jobs[jobs_index++]);
      }

      if(!pq.isEmpty()) { // 이전 작업 처리 중 요청된 작업이 있는 경우
        int[] job = pq.poll();
        answer += end_time - job[0] + job[1]; // 작업 요청부터 종료까지 걸린 시간 추가
        end_time += job[1]; // 작업 처리 완료 시간 갱신
        finish_job++; // 처리 완료된 작업 개수 1 증가
      } else { // 이전 작업 처리 중 요청된 작업이 없는 경우
        end_time = jobs[jobs_index][0]; // 다음 작업 요청 시점으로 갱신
      }
    }

    return answer / jobs.length;
  }
}

LV.3 이중우선순위큐

import java.util.*;

class Solution {
  public int[] solution(String[] operations) {
    Queue<Integer> minpq = new PriorityQueue<>();
    Queue<Integer> maxpq = new PriorityQueue<>(Collections.reverseOrder());

    for (String operation : operations) {
      if (operation.startsWith("I ")) {
        int n = Integer.parseInt(operation.substring(2));
        minpq.offer(n);
        maxpq.offer(n);

      } else if (!minpq.isEmpty() && operation.equals("D -1")) {
        maxpq.remove(minpq.poll());

      } else if (!maxpq.isEmpty() && operation.equals("D 1")) {
        minpq.remove(maxpq.poll());
      }
    }

    if (minpq.isEmpty() && maxpq.isEmpty()) {
      return new int[]{0, 0};
    }

    return new int[]{maxpq.poll(), minpq.poll()};
  }
}

정렬 문제 풀이

LV.1 K번째수

import java.util.*;

class Solution {
  public int[] solution(int[] array, int[][] commands) {
    int[] answer = new int[commands.length];
    
    for(int i = 0; i < commands.length; i++) {
      // 이차원 배열에서 배열 추출
      int[] command = Arrays.copyOfRange(array, commands[i][0]-1, commands[i][1]);
      
      // 오름차순 정렬
      Arrays.sort(command);
      
      // K번째 수
      answer[i] = command[commands[i][2]-1];
      
    }
    
    return answer;
  }
}

Arrays.toString, Arrays.deepToString 함수로 배열, 이차원배열 출력이 가능합니다.

내림차순 정렬은 Arrays.sort(command, Collections.reverseOrder()); 으로 할 수 있습니다.

LV.2 가장 큰 수

import java.util.*;

class Solution {
  public String solution(int[] numbers) {
    ArrayList<String> strList = new ArrayList<String>();
    
    // 각 int 원소를 String으로 변환
    for (int i = 0; i < numbers.length; i++) {
        strList.add(String.valueOf(numbers[i]));
    }
    
    // 앞뒤 원소 문자열 조합을 비교하며 오름차순 정렬
    Collections.sort(strList, (o1, o2) -> (o2 + o1).compareTo(o1 + o2));
    
    // 결과 String 연결
    StringBuilder sb = new StringBuilder();
    
    for (String str : strList) {
        sb.append(str);
    }
    
    String answer = sb.toString();
    
    // 원소가 [0, 0, 0]이면 0 반환, 외에는 그대로 반환
    return answer.charAt(0) == '0'? "0" : answer;
  }
}

compareTo 함수는 현재 객체가 다른 객체보다 작으면 크면 1, 음수, 같으면 0을 반환합니다.
(o2 + o1).compareTo(o1 + o2)은 반환값이 1이면 순서를 바꿔서, 내림차순 정렬됩니다.
(o1 + o2).compareTo(o2 + o1)은 반환값이 1이면 순서를 바꿔서, 오름차순 정렬됩니다.

문자열을 반복하여 더할 때 String += 대신 StringBuilder를 사용하면 메모리 효율적입니다.

answer.charAt(0) == ‘0’ 대신 answer.startsWith(“0”)를 사용해도 됩니다.

LV.2 H-Index

import java.util.*;

class Solution {
  public int solution(int[] citations) {
    int answer = 0;
    
    // 오름차순 정렬
    Arrays.sort(citations);
    
    for (int i = 0; i < citations.length; i++) {
      // 남은 논문의 개수
      int remainCnt = citations.length - i;
      
      // 현재 논문의 인용된 횟수가 남은 논문의 개수보다 크거나 같으면 반환
      if (citations[i] >= remainCnt) {
        answer = remainCnt;
        break;
      }
    }
    
    return answer;
  }
}

완전탐색 문제 풀이

LV.1 최소직사각형

class Solution {
  public int solution(int[][] sizes) {
    int w = 0, h = 0;

    // 모든 명함 반복
    for (int[] card : sizes) {
      // 명함의 가로, 세로를 비교해 큰 값 중 가장 큰 값이 지갑의 세로 길이가 됨
      w = Math.max(w, Math.max(card[0], card[1]));

      // 명함의 가로, 세로를 비교해 작은 값 중 가장 큰 값이 지갑의 세로 길이가 됨
      h = Math.max(h, Math.min(card[0], card[1]));
    }
    
    int answer = w * h;
    return answer;
  }
}

LV.1 모의고사 ★

import java.util.*;

class Solution {
  public int[] solution(int[] answers) {
      
    // 수포자 1, 2, 3 패턴 정의
    int[][] patterns = {
      {1, 2, 3, 4, 5},
      {2, 1, 2, 3, 2, 4, 2, 5},
      {3, 3, 1, 1, 2, 2, 4, 4, 5, 5}
    };
        
    // 각 수포자들의 정답 개수를 저장할 배열 초기화
    int[] hit = new int[3];
        
    // 각 수포자들의 패턴에 따라 정답을 비교하며 맞은 개수 계산
    for (int i = 0; i < hit.length; i++) {
      for (int j = 0; j < answers.length; j++) {
        if (patterns[i][j % patterns[i].length] == answers[j]) {
          hit[i]++;
        }
      }
    }
        
    // 가장 많은 정답을 맞은 수포자의 정답 개수 확인
    int max = Math.max(hit[0], Math.max(hit[1], hit[2]));
        
    // 가장 많은 정답을 맞은 수포자의 번호를 리스트에 저장
    ArrayList<Integer> list = new ArrayList<>();
    
    for (int i = 0; i < hit.length; i++) {
      if (hit[i] == max) {
        list.add(i+1);
      }
    }
        
    // 리스트에 저장된 수포자 번호를 배열로 변환하여 반환
    int[] answer = new int[list.size()];
    
    for (int i = 0; i < list.size(); i++) {
      answer[i] = list.get(i);
    }
    
    return answer;
  }
}

LV.2 소수 찾기

import java.util.HashSet;
class Solution {
  public int solution(String numbers) {
    HashSet<Integer> set = new HashSet<>();
    permutation("", numbers, set);
    int count = 0;
    while(set.iterator().hasNext()){
      int a = set.iterator().next();
      set.remove(a);
      if(a==2) count++;
      if(a%2!=0 && isPrime(a)){
        count++;
      }
    }
    return count;
  }

  public boolean isPrime(int n){
    if(n==0 || n==1) return false;
    for(int i=3; i<=(int)Math.sqrt(n); i+=2){
      if(n%i==0) return false;
    }
    return true;
  }

  public void permutation(String prefix, String str, HashSet<Integer> set) {
    int n = str.length();

    if(!prefix.equals("")) set.add(Integer.valueOf(prefix));

    for (int i = 0; i < n; i++) {
      permutation(prefix + str.charAt(i), str.substring(0, i) + str.substring(i+1, n), set);
    }
  }
}

LV.2 카펫

public class Solution {
  public int[] solution(int brown, int yellow) {
    // 격자의 총 개수 (파란색 격자 + 흰색 격자)
    int totalSize = brown + yellow;

    // 세로 길이의 범위는 3부터 (갈색 격자 + 노란색 격자)의 제곱근
    int sqrt = (int)Math.sqrt(totalSize);

    for (int vertical = 3; vertical <= sqrt; vertical++) {
      // 사격형 구성이 되는지 확인
      if (totalSize % vertical == 0) {
        // 사각형의 가로 길이
        int horizontal = (int)(totalSize / vertical);

        // 카펫 형태로 만들 수 있는지 확인
        if (brown == (horizontal + vertical - 2) * 2) {
          // [가로 길이, 세로 길이]
          return new int[]{horizontal, vertical};
        }
      }
    }

    // 만약 답을 찾지 못했다면 빈 리스트를 반환
    return new int[]{};
  }
}

LV.2 피로도

class Solution {
  public static boolean check[];
  public static int ans = 0;

  public int solution(int k, int[][] dungeons) {
    check = new boolean[dungeons.length];

    dfs(k, dungeons, 0);

    return ans;
  }

  public static void dfs(int tired, int[][] dungeons, int cnt){
    for (int i=0; i < dungeons.length; i++) {
      if (!check[i] && dungeons[i][0] <= tired) {
        check[i] = true;
        dfs(tired-dungeons[i][1], dungeons, cnt+1);
        check[i] = false;
      }
    }
    ans = Math.max(ans, cnt);
  }
}
public class Solution {
  private static int answer;
  private static int[][] Dungeons;
  private static boolean[] visited;

  // 백트래킹을 위한 DFS
  private static void backtrack(int k, int cnt) {
    for (int i = 0; i < Dungeons.length; i++) {
      // 현재 피로도(k)가 i번째 던전의 최소 필요 피로도보다 크거나 같고,
      // i번째 던전을 방문한 적이 없다면
      if (!visited[i] && k >= Dungeons[i][0]) {
        visited[i] = true; // i번째 던전을 방문 처리
        // 현재까지의 최대 탐험 가능 던전 수와
        // i번째 던전에서 이동할 수 있는 최대 탐험 가능 던전 수 중 큰 값을 선택하여 업데이트
        backtrack(k - Dungeons[i][1], cnt + 1);
        answer = Math.max(answer, cnt + 1);
        visited[i] = false; // i번째 던전을 다시 방문 취소
      }
    }
  }

  public int solution(int k, int[][] dungeons) {
    answer = 0;
    Dungeons = dungeons;

    // 던전 방문 여부를 저장할 배열
    visited = new boolean[dungeons.length];

    // DFS 메소드 수행
    backtrack(k, 0);

    return answer;
  }
}

LV.2 전력망을 둘로 나누기

class Solution {
  int N, min;
  int[][] map;
  int[] vst;

  int dfs(int n){
    vst[n] = 1;
    int child = 1;
    for(int i = 1; i <= N; i++) {
      if(vst[i] == 0 && map[n][i] == 1) {
        child += dfs(i);
      }
    }
    min = Math.min(min, Math.abs(child - (N - child)));
    return child;
  }

  public int solution(int n, int[][] wires) {
    N = n;
    min = n;
    map = new int[n+1][n+1];
    vst = new int[n+1];
    for(int[] wire : wires) {
      int a = wire[0], b = wire[1];
      map[a][b] = map[b][a] = 1;
    }
    dfs(1);
    return min;
  }
}
import java.util.ArrayList;

public class Solution {
  private static boolean[] visited;
  private static ArrayList<Integer>[] adjList;
  private static int N, answer;

  public static int solution(int n, int[][] wires) {
    N = n;
    answer = n - 1;

    // 전선의 연결 정보를 저장할 인접 리스트 초기화
    adjList = new ArrayList[n + 1];
    for (int i = 1; i <= n; i++) {
      adjList[i] = new ArrayList<>();
    }

    // 전선의 연결 정보를 인접 리스트에 저장
    for (int[] wire : wires) {
      adjList[wire[0]].add(wire[1]);
      adjList[wire[1]].add(wire[0]);
    }

    visited = new boolean[n + 1];

    // 깊이 우선 탐색 시작
    dfs(1);

    return answer;
  }

  private static int dfs(int now) {
    visited[now] = true;

    // 자식 노드의 수를 저장하고 반환할 변수 선언
    int sum = 0;

    // 연결된 모든 전선을 확인
    for (int next : adjList[now]) {
      if (!visited[next]) {
        // (전체 노드 - 자식 트리의 노드 수) - (자식 트리의 노드 수) 의 절대값이 가장 작은 값을 구함
        int cnt = dfs(next); // 자식 트리가 가진 노드의 수
        answer = Math.min(answer, Math.abs(N - cnt * 2));

        // 자식 노드의 수를 더함
        sum += cnt;
      }
    }

    // 전체 자식 노드의 수에 1(현재 now 노드)을 더해서 반환
    return sum + 1;
  }
}

LV.2 모음사전

import java.util.*;
class Solution {
  List<String> list = new ArrayList<>();
  
  void dfs(String str, int len) {
    if(len > 5) return;
    list.add(str);
    for(int i = 0; i < 5; i++) dfs(str + "AEIOU".charAt(i), len + 1);
  }
  
  public int solution(String word) {
    dfs("", 0);
    return list.indexOf(word);
  }
}

DFS를 이용한 완전탐색 방법입니다.
찾는 word 값 이후의 값도 탐색되지 않게 개선하면 좋을 것 같습니다.

탐욕법(Greedy) 문제 풀이

LV.1 체육복

class Solution {
  public int solution(int n, int[] lost, int[] reserve) {
    int[] people = new int[n];
    int answer = n;

    for (int l : lost) 
      people[l-1]--;
    for (int r : reserve) 
      people[r-1]++;

    for (int i = 0; i < people.length; i++) {
      if(people[i] == -1) {
        if(i-1>=0 && people[i-1] == 1) {
          people[i]++;
          people[i-1]--;
        }else if(i+1< people.length && people[i+1] == 1) {
          people[i]++;
          people[i+1]--;
        }else 
          answer--;
      }
    }
    return answer;
  }
}

배열 크기를 n+2로 선언하면 0과 마지막 인덱스를 더 잡을 수 있어서 if문 조건 하나씩 없앨 수 있습니다.

LV.2 조이스틱

class Solution {
  public int solution(String name) {
    int answer = 0;
    int[] diff={0,1,2,3,4,5,6,7,8,9,10,11,12,13,12,11,10,9,8,7,6,5,4,3,2,1};
    for(char c:name.toCharArray())
      answer+=diff[c-'A'];

    int length=name.length();
    int min=length-1;

    for(int i=0;i<length;i++){
      int next=i+1;
      while(next<length && name.charAt(next)=='A'){
        next++;
      }      

      min=Math.min(min,i+length-next+Math.min(i,length-next));
    }

    return answer+min;
  }
}

LV.2 큰 수 만들기

import java.util.Stack;

class Solution {
  public String solution(String number, int k) {
    char[] result = new char[number.length() - k];
    Stack<Character> stack = new Stack<>();

    for (int i=0; i<number.length(); i++) {
      char c = number.charAt(i);
      while (!stack.isEmpty() && stack.peek() < c && k-- > 0) {
        stack.pop();
      }
      stack.push(c);
    }
    for (int i=0; i<result.length; i++) {
      result[i] = stack.get(i);
    }
    return new String(result);
  }
}

LV.2 구명보트

import java.util.Arrays;

public class Solution {
  public int solution(int[] people, int limit) {
    // 몸무게를 오름차순으로 정렬
    Arrays.sort(people);
    
    // 필요한 보트 개수
    int count = 0;
    
    // 가장 가벼운 사람을 가리키는 인덱스
    int i = 0;

    // 가장 무거운 사람을 가르키는 인덱스
    int j = people.length - 1; 

    while (i <= j) {
      // 가장 무거운 사람과 가장 가벼운 사람을 같이 태울 수 있으면 두 사람 모두 보트에 태움
      if (people[i] + people[j] <= limit) {
        i += 1;
      }

      // 무거운 사람만 태울 수 있으면 무거운 사람만 보트에 태움
      j -= 1;
      count += 1;
    }

    return count;
  }
}

LV.3 섬 연결하기

import java.util.Arrays;

public class Solution {
  private static int[] parent;

  private static int find(int x) {
    // x가 속한 집합의 루트 노드 찾기
    if (parent[x] == x)
      return x;

    // 경로 압축: x의 부모를 루트로 설정
    return parent[x] = find(parent[x]);
  }

  private static void union(int x, int y) {
    // 두 집합을 하나의 집합으로 합치기
    int root1 = find(x);
    int root2 = find(y);
    parent[root2] = root1;
  }

  public int solution(int n, int[][] costs) {
    // 비용을 기준으로 다리를 오름차순 정렬
    Arrays.sort(costs, (o1, o2) -> Integer.compare(o1[2], o2[2]));

    // parent 배열 초기화
    parent = new int[n];
    for (int i = 0; i < n; i++) {
      parent[i] = i;
    }

    int answer = 0; // 최소 신장 트리의 총 비용
    int edges = 0; // 연결된 다리의 수

    for (int[] edge : costs) {
      // n - 1개의 다리가 연결된 경우 모든 섬이 연결됨
      if (edges == n - 1)
        break;

      // 현재 다리가 연결하는 두 섬이 이미 연결되어 있는지 확인
      if (find(edge[0]) != find(edge[1])) {
        // 두 섬을 하나의 집합으로 연결함
        union(edge[0], edge[1]);
        
        // 현재 다리의 건설 비용을 비용에 추가
        answer += edge[2];

        // 사용된 다리의 수 1증가
        edges++;
      }
    }

    return answer;
  }
}

LV.3 단속카메라

import java.util.Arrays;

class Solution {
  public int solution(int[][] routes) {
    Arrays.sort(routes, (a, b) -> Integer.compare(a[1], b[1]));
    int ans = 0;
    int last_camera = Integer.MIN_VALUE;
    for (int[] a : routes) {
      if (last_camera < a[0]) {
        ++ans;
        last_camera = a[1];
      }
    }
    return ans;
  }
}

동적계획법(Dynamic Programming) 문제 풀이

LV.3 N으로 표현

import java.util.HashSet;
import java.util.Set;

class Solution {
  public int solution(int N, int number) {
    int answer = -1;
    Set<Integer>[] setArr = new Set[9];
    int t = N;

    for(int i = 1; i < 9; i++) {
      setArr[i] = new HashSet<>();
      setArr[i].add(t);
      t = t * 10 + N;
    }

    for(int i = 1; i < 9; i++) {
      for(int j = 1; j < i; j++) {
        for(Integer a : setArr[j]) {
          for(Integer b : setArr[i - j]) {
            setArr[i].add(a + b);
            setArr[i].add(a - b);
            setArr[i].add(b - a);
            setArr[i].add(a * b);
            if(b != 0) {
              setArr[i].add(a / b);
            }
            if(a != 0) {
              setArr[i].add(b / a);
            }
          }
        }
      }
    }

    for(int i = 1; i < 9; i++) {
      if(setArr[i].contains(number)) {
        answer = i;
        break;
      }
    }

    return answer;
  }
}

LV.3 정수 삼각형

import java.util.*;

class Solution {
  public int solution(int[][] triangle) {
    for (int i = 1; i < triangle.length; i++) {
      triangle[i][0] += triangle[i-1][0];
      triangle[i][i] += triangle[i-1][i-1];

      for (int j = 1; j < i; j++) 
        triangle[i][j] += Math.max(triangle[i-1][j-1], triangle[i-1][j]);
    }

    return Arrays.stream(triangle[triangle.length-1]).max().getAsInt();
  }
}
public class Solution {
  public int solution(int[][] triangle) {
    int n = triangle.length;

    // dp 배열 초기화
    int[][] dp = new int[n][n];

    // dp 배열의 맨 아래쪽 라인 초기화
    for (int i = 0; i < n; i++) {
      dp[n - 1][i] = triangle[n - 1][i];
    }

    // 아래쪽 라인부터 올라가면서 dp 배열 채우기
    for (int i = n - 2; i >= 0; i--) {
      for (int j = 0; j <= i; j++) {
        dp[i][j] = Math.max(dp[i + 1][j], dp[i + 1][j + 1]) + triangle[i][j];
      }
    }

    // 꼭대기에서의 최댓값 반환
    return dp[0][0];
  }
}

LV.3 등굣길

class Solution {
  public int solution(int m, int n, int[][] puddles) {
    int[][] dp = new int[m+1][n+1];

    for(int i=0;i<puddles.length;i++){
        dp[puddles[i][0]][puddles[i][1]]=-1;
    }

    dp[1][1]=1; 
    for(int i=1;i<=m;i++){
      for(int j=1;j<=n;j++){
        if(dp[i][j]==-1){
          dp[i][j]=0;
          continue;
        }
        if(i!=1) dp[i][j]+=dp[i-1][j]%1000000007;
        if(j!=1) dp[i][j]+=dp[i][j-1]%1000000007;
      }
    }

    return dp[m][n]%1000000007;
  }
}

LV.4 사칙연산

class Solution {
  int[][] minMem = new int[210][210];
  boolean[][] minVisited = new boolean[210][210];
  int[][] maxMem = new int[210][210];
  boolean[][] maxVisited = new boolean[210][210];

  public int solution(String arr[]) {
    return computeMax(arr, 0, arr.length-1);
  }

  int computeMax(String[] arr, int s, int e) {
    if(s == e) return Integer.parseInt(arr[s]);
    if(maxVisited[s][e]) return maxMem[s][e];
    int r = Integer.MIN_VALUE;
    for(int i = s; i <= e-2; i += 2) {
      if(arr[i+1].equals("+")) {
        r = Math.max(r, computeMax(arr, s, i) + computeMax(arr, i+2, e));
      } else {
        r = Math.max(r, computeMax(arr, s, i) - computeMin(arr, i+2, e));
      }
    }
    maxVisited[s][e] = true;
    maxMem[s][e] = r;
    return r;
  }

  int computeMin(String[] arr, int s, int e) {
    if(s == e) return Integer.parseInt(arr[s]);
    if(minVisited[s][e]) return minMem[s][e];
    int r = Integer.MAX_VALUE;
    for(int i = s; i <= e-2; i += 2) {
      if(arr[i+1].equals("+")) {
        r = Math.min(r, computeMin(arr, s, i) + computeMin(arr, i+2, e));
      } else {
        r = Math.min(r, computeMin(arr, s, i) - computeMax(arr, i+2, e));
      }
    }
    minVisited[s][e] = true;
    minMem[s][e] = r;
    return r;
  }
}

LV.4 도둑질

class Solution {
  public int solution(int[] money) {        
    int[][] pick = new int[2][money.length];

    pick[0][0] = money[0];
    pick[0][1] = money[0];
    pick[1][0] = 0;
    pick[1][1] = money[1];

    for(int i=2; i<money.length; i++) {
      pick[0][i] = Math.max(pick[0][i-2] + money[i], pick[0][i-1]);
      pick[1][i] = Math.max(pick[1][i-2] + money[i], pick[1][i-1]);
    }

    return Math.max(pick[0][pick[0].length-2], pick[1][pick[1].length-1]);
  }
}
public class Solution {
  public int solution(int[] money) {
    // 점화식에 필요한 변수를 초기화
    int n = money.length;
    int[] dp1 = new int[n];
    int[] dp2 = new int[n];

    // 첫 번째 집을 도둑질하는 경우
    dp1[0] = money[0];
    dp1[1] = money[0];
    for (int i = 2; i < n - 1; i++) {
      dp1[i] = Math.max(dp1[i - 1], dp1[i - 2] + money[i]);
    }

    // 첫 번째 집을 도둑질하지 않는 경우
    dp2[1] = money[1];
    for (int i = 2; i < n; i++) {
      dp2[i] = Math.max(dp2[i - 1], dp2[i - 2] + money[i]);
    }

    // 두 경우 중 최댓값 찾기
    return Math.max(dp1[n - 2], dp2[n - 1]);
  }
}

깊이/너비 우선 탐색(DFS/BFS) 문제 풀이

LV.2 타겟 넘버

class Solution {
  public int solution(int[] numbers, int target) {
    // DFS로 타겟 숫자를 만들 수 있는 경우의 수 리턴
    return dfs(numbers, target, 0, 0);
  }
  
  public int dfs(int[] numbers, int target, int sum, int n) {
    // 숫자 배열을 모두 탐색한 경우
    if (n == numbers.length) {
      // 합이 타겟 숫자와 같으면 경우의 수 1 반환
      if (sum == target) {
        return 1;
      } else {
        // 합이 타겟 숫자와 다르면 경우의 수 0 반환
        return 0;
      }
    }
    
    // 현재 숫자를 빼거나 더하고, 다음 숫자 탐색을 반복하여 경우의 수 합산
    return dfs(numbers, target, sum - numbers[n], n + 1) + dfs(numbers, target, sum + numbers[n], n + 1);
  }
}

LV.3 네트워크

class Solution {
  public int solution(int n, int[][] computers) {
    // 네트워크 개수
    int answer = 0;
    
    // 컴퓨터 방문 여부 체크 배열
    boolean[] visited = new boolean[n];
    
    // 모든 컴퓨터를 순회하면서 방문하지 않은 컴퓨터에 DFS 수행
    for (int i = 0; i < n; i++) {
      if (!visited[i]) {
        dfs(n, computers, i, visited);
        
        // 새로운 네트워크 발견
        answer++;
      }
    }
    
    // 전체 네트워크 개수 반환
    return answer;
  }
  
  public void dfs(int n, int[][] computers, int i, boolean[] visited) {
    // 현재 컴퓨터 방문 표시
    visited[i] = true;
    
    for (int j = 0; j < n; j++) {
      // 현재 컴퓨터와 연결된 컴퓨터 중 방문하지 않은 컴퓨터에 재귀적 DFS 수행
      if (computers[i][j] == 1 && !visited[j]) {
        dfs(n, computers, j, visited);
      }
    }
  }
}

LV.2 게임 맵 최단거리

import java.util.*;

class Solution {
  public int solution(int[][] maps) {
    // 지도의 행과 열의 개수
    int rows = maps.length;
    int cols = maps[0].length;
    
    // 이동할 수 있는 방향 (상, 하, 좌, 우)
    int[][] moves = new int[][] { {0, -1}, {0, 1}, {-1, 0}, {1, 0} };
    
    // BFS를 위한 큐 선언
    Queue<int[]> queue = new ArrayDeque<>();
    
    // 시작 위치와 이동 거리(칸 수)를 큐에 넣음
    queue.offer(new int[] {0, 0, 1});
    
    // BFS 탐색
    while(!queue.isEmpty()) {
      // 큐에서 현재 위치와 거리 정보를 꺼냄
      int[] cur_node = queue.poll();
      
      int row = cur_node[0];
      int col = cur_node[1];
      int move_cnt = cur_node[2];
      
      // 목적지에 도달한 경우 현재까지의 최단거리 반환
      if (row == rows-1 && col == cols-1) {
        return move_cnt;
      }
      
      // 네 방향을 방문하여 갈 수 있는 위치면 큐에 추가
      for (int[] move : moves) {
        int next_row = row + move[1];
        int next_col = col + move[0];
          
        // 새로운 위치가 지도 내에 있는 경우
        if (next_row >= 0 && next_row < rows && next_col >= 0 && next_col < cols) {
          // 갈 수 없는 곳이거나 방문한 곳이면 건너띄움
          if (maps[next_row][next_col] == 0) {
            continue;
          }

          // 처음 방문하여, 재방문하지 않도록 방문 처리
          maps[next_row][next_col] = 0;
          
          // 새로운 위치와 이동 거리를 큐에 추가
          queue.offer(new int[] {next_row, next_col, move_cnt + 1});
        }
      }
    }
    
    // 목적지에 도달할 수 없는 경우
    return -1;
  }
}

LV.3 단어 변환

import java.util.*;

class Solution {

  // 내부 클래스로 노드 정의
  public class Node {
    String cur_word; // 현재 단어
    int change_cnt; // 변환 횟수

    public Node(String cur_word, int change_cnt) {
      this.cur_word = cur_word;
      this.change_cnt = change_cnt;
    }
  }

  public int solution(String begin, String target, String[] words) {
    // BFS 탐색을 위한 큐 생성
    Queue<Node> queue = new ArrayDeque<>();

    // 방문 여부를 나타내는 배열 생성
    boolean[] visited = new boolean[words.length];
	
    // 큐에 시작 단어 추가, 변환 횟수는 0으로 초기화
    queue.add(new Node(begin, 0));

    // BFS 탐색 시작
    while (!queue.isEmpty()) {
      Node node = queue.poll();
	  
      // 현재 단어가 목표 단어와 같으면
      if (node.cur_word.equals(target)) {
        // 현재까지의 변환 횟수 반환
        return node.change_cnt;
      }

      // 단어 리스트 순회하며 변환 가능한 다음 단어 탐색
      for (int i = 0; i < words.length; i++) {
        // 방문하지 않은 단어이고, 현재 단어에서 다음 단어를 한 글자만 바꿔서 만들 수 있다면
        if (!visited[i] && isNext(node.cur_word, words[i])) { 
          // 다음 단어 방문 표시
          visited[i] = true;
		  
          // 큐에 다음 단어 추가, 변환 횟수 1 증가
          queue.add(new Node(words[i], node.change_cnt + 1));
        }
      }
    }
    
    // target 단어가 없는 경우
    return 0;
  }

  // 두 단어가 한 글자만 다른지 확인하는 함수
  static boolean isNext(String cur_str, String next_str) {
    int diff_cnt = 0;
	
    for (int i = 0; i < next_str.length(); i++) {
      if (cur_str.charAt(i) != next_str.charAt(i)) {
        // 두 단어의 같은 인덱스 비교 후 다르면 카운트 증가
        diff_cnt++;
      
        // 한 글자만 다른 경우가 아니라면 false 반환
        if (diff_cnt > 1) {
          return false;
        }
      }
    }

    // 한 글자만 다른 경우 true 반환
    return true;
  }
}

LV.3 아이템 줍기

import java.util.*;

class Solution {
  // 상하좌우 이동을 위한 배열
  int[][] moves = { {0, 1}, {0, -1}, {-1, 0}, {1, 0} };

  public int solution(int[][] rectangle, int characterX, int characterY, int itemX, int itemY) {
    int answer = 0;

    // 경계면 이동 시 최단거리 정확도를 높이기 위해 모든 좌표를 2배로 확장
    characterX *= 2;
    characterY *= 2;
    itemX *= 2;
    itemY *= 2;

    for(int i = 0; i < rectangle.length; i++) {
      var rec = rectangle[i];
      rectangle[i] = new int[] { rec[0] * 2, rec[1] * 2, rec[2] * 2, rec[3] * 2};
    }

    // 사각형 영역을 표시하는 맵 생성
    boolean[][] map = new boolean[102][102], vst = new boolean[102][102];

    // 사각형 좌표를 이용하여 맵에 사각형 표시
    for(int[] rec : rectangle) {
      for(int i = rec[0]; i <= rec[2]; i++) {
        for(int j = rec[1]; j <= rec[3]; j++) {
          map[i][j] = true;
        }
      }
    }
    
    // 사각형 내부에 있는 픽셀을 제거하여 테두리만 남김
    Queue<int[]> q = new LinkedList<>();
    for(int i = 1; i <= 100; i++) {
      for(int j = 1; j <= 100; j++) {
        int inner = 0;

        for(int[] rec : rectangle) {
            if(rec[0] < i && i < rec[2] && rec[1] < j && j < rec[3]) inner++;
        }
        
        if(inner != 0) q.add(new int[] { i, j });
      }
    }

    // 테두리 좌표를 이용하여 맵에서 내부 제거
    for(int[] p : q) map[p[0]][p[1]] = false;
    
    // BFS를 사용하여 최단 경로 계산
    q = new LinkedList<>();
    q.add(new int[] { characterX, characterY, 0 });
    vst[characterX][characterY] = true;
    
    while(!q.isEmpty()) {
      int[] p = q.poll();

      // 아이템에 도달하면 이동 횟수를 저장
      if(p[0] == itemX && p[1] == itemY) {
        answer = p[2] / 2;
        break;
      }
      
      // 상하좌우 이동을 시도하며, 이동 가능한 경우 큐에 추가
      for(int i = 0; i < moves.length; i++) {
        int x = p[0] + moves[i][0];
        int y = p[1] + moves[i][1];

        if(0 <= x && 0 <= y && x < 102 && y < 102 && !vst[x][y] && map[x][y]) {
          q.add(new int[] {x, y, p[2] + 1});

          // 큐에 추가 후 방문 처리
          vst[x][y] = true;
        }
      }
    }

    return answer;
  }
}

LV.3 여행경로

import java.util.*;

class Solution {
  List<Stack<String>> result;
  String[][] tickets;

  public String[] solution(String[][] tickets) {
    result = new ArrayList<>();
    this.tickets = tickets;

    boolean[] visited = new boolean[tickets.length];
    Stack<String> st = new Stack<>();
    st.push("ICN");

    dfs(visited, st, 0);

    if (result.size() > 1) {
      Collections.sort(result, new Comparator<Stack<String>>() {
        @Override
        public int compare(Stack<String> o1, Stack<String> o2) {
          for (int i = 0; i < o1.size(); i++) {
            String s1 = o1.get(i);
            String s2 = o2.get(i);

            if (!s1.equals(s2)) {
              return s1.compareTo(s2);
            }
          }

          return 0;
        }
      });
    }

    Stack<String> res = result.remove(0);
    String[] answer = new String[res.size()];

    for (int i = 0; i < answer.length; i++) {
      answer[i] = res.get(i);
    }

    return answer;
  }

  public void dfs(boolean[] visited, Stack<String> st, int len) {
    if (len == tickets.length) {
      Stack<String> res = new Stack<>();
      for (String s : st) {
        res.push(s);
      }

      result.add(res);
      return;
    }

    String arrive = st.peek();

    for (int i = 0; i < tickets.length; i++) {
      String[] tic = tickets[i];

      if (!visited[i] && arrive.equals(tic[0])) {
        st.push(tic[1]);
        visited[i] = true;

        dfs(visited, st, len + 1);

        visited[i] = false;
        st.pop();
      }
    }
  }
}

LV.3 퍼즐 조각 채우기

import java.util.*;

class Solution {
  public class Node {
      int x, y;

      Node(int x, int y) {
          this.x = x;
          this.y = y;
      }
  }
  public ArrayList<String> emptyList = new ArrayList<>();
  public int N;
  public int[] dx = {0, 0, -1, 1};
  public int[] dy = {-1, 1, 0, 0};

  public int solution(int[][] game_board, int[][] table) {
      N = game_board.length;
      int answer = 0;

      for(int i = 0; i < N; i++) {
          for(int j = 0; j < N ; j++) {
              if(game_board[i][j] == 0) {
                  emptyList.add(bfs(game_board, i, j, 0));
              }
          }
      }

      for(int i = 0; i < N; i++) {
          for(int j = 0; j < N ; j++) {
              if(table[i][j] == 1) {
                  answer += find(bfs(table, i, j, 1));
              }
          }
      }

      return answer;
  }

  public int find(String s) {
      int point = 0;

      for(int i = 0; i < s.length(); i++) {
          if(s.charAt(i) == '1') point++;
      }

      for(int i = 0; i < emptyList.size(); i++) {
          String str = emptyList.get(i);

          for(int j = 0; j < 4; j++) {
              str = rotate(str);
              // System.out.println(str);
              if(s.equals(str)) {
                  emptyList.remove(i);
                  return point;
              }
          }
      }

      return 0;
  }

  public String rotate(String s) {
    String str = "";
    int x = 0;
    int y = 0;

    for(int i = 0; i < s.length(); i++) {
      if(x == 0) {
        if(s.charAt(i) != ' ') {
          y++;
        }
      }
      if(s.charAt(i) == ' ') {
        x++;
      }
    }

    char[][] arr = new char[x][y];
    StringTokenizer st = new StringTokenizer(s);

    for(int i = 0; i < x; i++) {
      arr[i] = st.nextToken().toCharArray();
    }

    for(int j = 0; j < y; j++) {
      for(int i = x - 1; i >= 0; i--) {
        str += arr[i][j];
      }
      str += " ";
    }

    return str;
  }

  public String bfs(int[][] arr, int i, int j, int mode) {
    // mode 0 : game_board, mode 1 : table
    String s = "";
    ArrayDeque<Node> q = new ArrayDeque<>();
    boolean[][] tmp = new boolean[N][N];

    int x_min = i;
    int x_max = i;
    int y_min = j;
    int y_max = j;

    tmp[i][j] = true;
    arr[i][j] = (mode + 1) % 2;
    q.add(new Node(i, j));

    while(!q.isEmpty()) {
      Node cur = q.poll();
      int x = cur.x;
      int y = cur.y;

      x_min = Math.min(x_min, x);
      x_max = Math.max(x_max, x);
      y_min = Math.min(y_min, y);
      y_max = Math.max(y_max, y);

      for(int k = 0; k < 4; k++) {
        int nx = x + dx[k];
        int ny = y + dy[k];

        if(!isBoundary(nx, ny)) continue;

        if(arr[nx][ny] == mode) {
          tmp[nx][ny] = true;
          arr[nx][ny] = (mode + 1) % 2;
          q.add(new Node(nx, ny));
        }
      }
    }

    for(int x = x_min; x <= x_max; x++) {
      for(int y = y_min; y <= y_max; y++) {
        s += tmp[x][y] ? "1" : "0";
      }
      s += " ";
    }

    return s;
  }

  public boolean isBoundary(int x, int y) {
    return x >= 0 && x < N && y >= 0 && y < N;
  }
}

이분탐색 문제 풀이

LV.3 입국심사

import java.util.Arrays;
class Solution {
  public long solution(int n, int[] times) {
    long answer = 0;
    Arrays.sort(times);
    long left = 0;
    long right = times[times.length-1] * (long)n; //모든 사람이 가장 느리게 심사받음
    
    while(left <= right) {
      long mid = (left + right) / 2;
      long complete = 0;
      for (int i = 0; i < times.length; i++)
        complete += mid / times[i];
      if (complete < n) // 해당 시간에는 모든 사람이 검사받을 수 없다.
        left = mid + 1;
      else {
        right = mid - 1;
        answer = mid; // 모두 검사받았으나, 더 최솟값이 있을 수 있다.
      }
    }  
    return answer;
  }
}

LV.4 징검다리

import java.util.*;

class Solution {
  public int solution(int distance, int[] rocks, int n) {
    int answer = 0;

    Arrays.sort(rocks);
    
    int left = 1;
    int right = distance;

    while(left <= right){
      int mid = (left + right)/2;
      if(getRemovedRockCnt(rocks, mid, distance) <= n){
        answer = mid;
        left = mid + 1;
      } else {
        right = mid - 1; 
      }
    }
    
    return answer;
  }
  
  public int getRemovedRockCnt(int[] rocks, int mid, int distance){
    // mid가 바위(지점) 간 최소 거리가 되어야 함
    // 그렇게 하기 위해 제거 해야할 바위의 개수를 리턴한다. 
    int before = 0; 
    int end = distance;
    
    int removeCnt = 0;

    for(int i = 0; i < rocks.length; i++){
      if(rocks[i] - before < mid) {
        removeCnt++;
        continue;
      }

      before = rocks[i];
    }

    if(end - before < mid) removeCnt++;

    return removeCnt;
  }
}

그래프 문제 풀이

LV.3 가장 먼 노드

import java.util.ArrayList;

class Solution {
  public int solution(int n, int[][] edge) {
    ArrayList<Integer>[] path = new ArrayList[n];
    ArrayList<Integer> bfs = new ArrayList<Integer>();
    int answer = 0;
    int[] dist = new int[n];
    dist[0] = 1;
    int max = 0;

    for(int i = 0; i < edge.length; i++) {
      int num1 = edge[i][0] - 1;
      int num2 = edge[i][1] - 1;

      if(path[num1] == null)
        path[num1] = new ArrayList<Integer>();

      if(path[num2] == null)
        path[num2] = new ArrayList<Integer>();

      path[num1].add(num2);
      path[num2].add(num1);
    }

    bfs.add(0);

    while(!bfs.isEmpty()) {
      int idx = bfs.get(0);
      bfs.remove(0);
      while(!path[idx].isEmpty()) {
        int num = path[idx].get(0);
        path[idx].remove(0);
        bfs.add(num);

        if(dist[num] == 0) {
          dist[num] = dist[idx] + 1;
          max = dist[num];
        }
      }
    }

    for(int i = 0; i < n; i++) {
      if(dist[i] == max)
        answer++;
    }

    return answer;
  }
}

LV.3 순위

class Solution {
  public int solution(int n, int[][] results) {
    int answer = 0;

    boolean[][] chk = new boolean[n + 1][n + 1];

    for(int i = 0; i < results.length; i++) {
      chk[results[i][0]][results[i][1]] = true;
    }

    for(int k = 1; k < n + 1; k++) {
      for(int i = 1; i < n + 1; i++) {
        for(int j = 1; j < n + 1; j++) {
          if(i != j && chk[i][k] && chk[k][j]) {
            chk[i][j] = true;
          }
        }
      }
    }

    for(int i = 1; i < n + 1; i++) {
      boolean pass = true;

      for(int j = 1; j < n + 1; j++) {
        if(i != j && !(chk[i][j] || chk[j][i])) {
          pass = false;
          break;
        }
      }

      if(pass) {
        answer++;
      }
    }

    return answer;
  }
}

LV.5 방의 개수

import java.util.HashSet;
import java.util.Set;

class Solution {
  public int solution(int[] arrows) {
      int answer = 0;
      Set<String> lineSet = new HashSet<String>();
      Set<String> pointSet = new HashSet<String>();
      int x = 0;
      int y = 0;
      pointSet.add("" + x+"|"+y);
      for (int i = 0; i < arrows.length; i++) {
        for(int j = 0; j < 2; j++){
          int vect = arrows[i];
          String start = ""+ x+"|"+y;

          if(vect<=1 || vect==7) y++;
          if(1<=vect && vect<=3) x++;
          if(3<=vect && vect<=5) y--;
          if(5<=vect && vect<=7) x--;

          String point = "" + x+"|"+y;
          String normalLine = start +"|" + point; 
          String backLine =  point + "|" + start; 

          if(pointSet.contains(point)){
            if(!lineSet.contains(normalLine)){
              answer++;
            }
          }

          pointSet.add(point);
          lineSet.add(normalLine);
          lineSet.add(backLine);
        }
      }

      return answer;
  }
}

Leave a comment