Java/코딩테스트

프로그래머스 - 숫자 변환하기, 택배 배달과 수거하기, 백준 16918

Bubbles 2023. 10. 28. 02:45

🔢 프로그래머스 : 숫자 변환하기

https://school.programmers.co.kr/learn/courses/30/lessons/154538

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

자연수 x를 y로 변환하려고 합니다. 사용할 수 있는 연산은 다음과 같습니다.

  • x에 n을 더합니다
  • x에 2를 곱합니다.
  • x에 3을 곱합니다.

자연수 x, y, n이 매개변수로 주어질 때, x를 y로 변환하기 위해 필요한 최소 연산 횟수를 return하도록 solution 함수를 완성해주세요. 이때 x를 y로 만들 수 없다면 -1을 return 해주세요.

 

🔢 이 문제 예전에 백준에서 본 문제와 유사하다고 생각했는데, 백준 1463 - 1로 만들기 이 문제와 유사하다. 

🔢 동적 계획법, BFS 다 가능한 문제 

 

🔢 동적 계획법 코드

class Solution {
    public int solution(int x, int y, int n) {
        int[] DP = new int[y+1];
        for (int i = x + 1; i <= y; i++) {
            int temp = 1000010;
            if (i >= n && i - n >= x) {
                temp = Math.min(temp, DP[i - n] + 1);
            } 
            if (i / 2 >= x && i % 2 == 0) {
                temp = Math.min(temp, DP[i / 2] + 1);
            }
            if (i / 3 >= x && i % 3 == 0) {
                temp = Math.min(temp, DP[i / 3] + 1);
            }
            
            DP[i] = temp;
        }
        
        return DP[y] >= 1000010 ? -1 : DP[y];
    }
}

 

🔢 BFS 코드

import java.util.*;
class Solution {
    public int solution(int x, int y, int n) {
        boolean[] visited = new boolean[y+1];
        Queue<Num> queue = new LinkedList<>();
        queue.add(new Num(x, 0));
        visited[x] = true;
        
        while (!queue.isEmpty()) {
            Num poll = queue.poll();
            if (poll.value == y) {
                return poll.count;
            }
            
            if (poll.value * 2 <= y && !visited[poll.value * 2]) {
                queue.add(new Num(poll.value * 2, poll.count+1));
                visited[poll.value * 2] = true;
            }
            
            if (poll.value * 3 <= y && !visited[poll.value * 3]) {
                queue.add(new Num(poll.value * 3, poll.count + 1));
                visited[poll.value * 3] = true;
            }
            
            if (poll.value + n <= y && !visited[poll.value + n]) {
                queue.add(new Num(poll.value + n, poll.count + 1));
                visited[poll.value + n] = true;
            }
        }
        
        return -1;
    }
    
    class Num {
        int value;
        int count;
        
        Num (int value, int count) {
            this.value = value;
            this.count = count;
        }
    }
    
}

 

🔢 이건 코드와 별개로 궁금해서 두 테스트 결과를 모두 캡처 떠왔는데, 왼쪽이 DP 오른쪽이 BFS이다. 

🔢 프로그래머스에서 테스트 케이스를 공개하지는 않는데, 몇 번 돌려보니 5, 6, 9, 10, 11 이 쪽이 데이터가 많은 테스트인 것 같았다(처음에 여기서 시간초과 났음)

🔢 비교적 DP가 BFS보다 시간소모가 일정하게 나오는 것 같긴 하다. 

 

 

 


📦 프로그래머스 : 택배 배달과 수거하기

https://school.programmers.co.kr/learn/courses/30/lessons/150369

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 

 

📦 뒤에 있는 것들을 빠르게 해치우는 것이 최대한 적게 움직일 수 있다. 

 

 

📦 배달을 해 준 만큼 수거도 가능하다. 따라서 cap만큼 (한 번에 실어나를 수 있는 양) 마지막 칸에 다 내려주고, 내려준 크기만큼 수거해간다. 

📦 코드 로직

  • if 문 : 배달 / 수거 해가야 할 양이 남아있다면
  • while 문 : cap만큼 배달 / 수거를 하면서 count를 증가시킨다. 
  • 다 도달하면 deliver / pick은 각 지점에서의 배달 / 수거 양이므로 다시 빼준다. 
  • answer += count * (i + 1) * 2 
    • count는 해당 지점에 들려야하는 횟수이다. 왕복이므로 * 2, index는 1부터 시작하므로 i + 1

 

📦 전체코드 

class Solution {
    public long solution(int cap, int n, int[] deliveries, int[] pickups) {
        long answer = 0;
        int deliver = 0;
        int pick = 0;
    
        for (int i = n-1; i >= 0; i--) {
            int count = 0;
            if (deliveries[i] > 0 || pickups[i] > 0) {
                while (deliver < deliveries[i] || pick < pickups[i]) {
                    count++;
                    deliver += cap;
                    pick += cap;
                }
                deliver -= deliveries[i];
                pick -= pickups[i];
                
                answer += count * (i+1) * 2;
            }
        }
        return answer;
    }
}

 

 

 

 

 

 


 

💣 백준 16918 : 봄버맨

https://www.acmicpc.net/problem/16918

 

16918번: 봄버맨

첫째 줄에 R, C, N (1 ≤ R, C, N ≤ 200)이 주어진다. 둘째 줄부터 R개의 줄에 격자판의 초기 상태가 주어진다. 빈 칸은 '.'로, 폭탄은 'O'로 주어진다.

www.acmicpc.net

 

💣 실버1 문제인데 생각보다 구현할 때 헷갈렸던 문제... (내가 물골드...인걸수도

💣 문제의 상황을 해석해보면 아래와 같다. 

  • 0초 : 초기상태
  • 1초 : 봄버맨 안 움직임
  • 2초 : 빈칸에 폭탄 설치
  • 3초 : 폭탄이 터짐(초기에 설치한)
  • 4초 : 빈칸에 폭탄 설치
  • 5초 : 폭탄이 터짐(2초에 설치한) 
  • 6초 : 빈칸에 폭탄 설치 

💣 코드 흐름 

  • 0, 1초를 제외하면 계속 짝수 초에는 폭탄 설치, 홀수 초에는 폭탄 폭발 이렇게 번갈아가면서 일어나는 것을 볼 수 있다. 
  • 따라서 아래 코드처럼 먼저 curTime(현재 시간)을 +1 해주고, while문을 시작한다.
  • 짝수일 때는 폭탄 설치(setBomb())
  • 홀수 일때는 bombLife로 터질 위치 계산하고, burst로 터뜨린다. temp는 터지는 애들 표기용 임시 배열
curTime++;
while (curTime <= time) {
	if (curTime % 2 == 0) {
		setBomb();
	} else {
		bombLife();
		burst();
		temp = new int[row][col];
	}
	curTime++;
}

 

 

💣 전체코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
    private static char[][] map;
    private static int[][] timeMap, temp;
    private static int[] dirX = { -1, 0, 1, 0};
    private static int[] dirY = {0, 1, 0, -1};
    private static int row, col, time, curTime = 0;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        row = Integer.parseInt(st.nextToken());
        col = Integer.parseInt(st.nextToken());
        time = Integer.parseInt(st.nextToken());

        map = new char[row][col];
        temp = new int[row][col];
        timeMap = new int[row][col];
        for (int i = 0; i < row; i++) {
            String str = br.readLine();
            for (int j = 0; j < col; j++) {
                map[i][j] = str.charAt(j);
                if (map[i][j] == 'O') {
                    timeMap[i][j] = 3;
                }
            }
        }
        curTime++;
        
        // 2초부터 시작
        while (curTime <= time) {

            if (curTime % 2 == 0) {
                setBomb();
            } else {
                bombLife();
                burst();
                temp = new int[row][col];
            }
            curTime++;
        }

        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                System.out.print(map[i][j]);
            }
            System.out.println();
        }
    }

    // 폭탄 설치
    private static void setBomb() {
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                if (map[i][j] == '.') {
                    map[i][j] = 'O';
                    timeMap[i][j] = curTime + 3;
                }
            }
        }
    }

    // 터진 애들 빈칸으로 한번에 만들어주기
    private static void burst() {
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                if (temp[i][j] == -1) {
                    map[i][j] = '.';
                    timeMap[i][j] = 0;
                }
            }
        }
    }

    private static void bombLife() {
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                if (timeMap[i][j] == curTime) {
                    temp[i][j] = -1;
                    findBurstSpot(i, j);
                }
            }
        }

    }

    private static void findBurstSpot(int x, int y) {
        for (int i = 0; i < 4; i++) {
            int nextX = x + dirX[i];
            int nextY = y + dirY[i];

            if (nextX < 0 || nextX >= row || nextY < 0 || nextY >= col) {
                continue;
            }
            if (temp[nextX][nextY] == -1) {
                continue;
            }
            if (timeMap[nextX][nextY] == curTime) {
                continue;
            }
            map[nextX][nextY] = '.';
            timeMap[nextX][nextY] = 0;
        }
    }

}