[프로그래머스][Lv.1][JAVA][PCCP 기출문제]1번/붕대 감기
문제
어떤 게임에는 붕대 감기라는 기술이 있습니다.
붕대 감기는 t초 동안 붕대를 감으면서 1초마다 x만큼의 체력을 회복합니다. t초 연속으로 붕대를 감는 데 성공한다면 y만큼의 체력을 추가로 회복합니다. 게임 캐릭터에는 최대 체력이 존재해 현재 체력이 최대 체력보다 커지는 것은 불가능합니다.
기술을 쓰는 도중 몬스터에게 공격을 당하면 기술이 취소되고, 공격을 당하는 순간에는 체력을 회복할 수 없습니다. 몬스터에게 공격당해 기술이 취소당하거나 기술이 끝나면 그 즉시 붕대 감기를 다시 사용하며, 연속 성공 시간이 0으로 초기화됩니다.
몬스터의 공격을 받으면 정해진 피해량만큼 현재 체력이 줄어듭니다. 이때, 현재 체력이 0 이하가 되면 캐릭터가 죽으며 더 이상 체력을 회복할 수 없습니다.
당신은 붕대감기 기술의 정보, 캐릭터가 가진 최대 체력과 몬스터의 공격 패턴이 주어질 때 캐릭터가 끝까지 생존할 수 있는지 궁금합니다.
붕대 감기 기술의 시전 시간, 1초당 회복량, 추가 회복량을 담은 1차원 정수 배열 bandage와 최대 체력을 의미하는 정수 health, 몬스터의 공격 시간과 피해량을 담은 2차원 정수 배열 attacks가 매개변수로 주어집니다. 모든 공격이 끝난 직후 남은 체력을 return 하도록 solution 함수를 완성해 주세요. 만약 몬스터의 공격을 받고 캐릭터의 체력이 0 이하가 되어 죽는다면 -1을 return 해주세요.
제한사항
- bandage는 [시전 시간, 초당 회복량, 추가 회복량] 형태의 길이가 3인 정수 배열입니다.
- 1 ≤ 시전 시간 = t ≤ 50
- 1 ≤ 초당 회복량 = x ≤ 100
- 1 ≤ 추가 회복량 = y ≤ 100
- 1 ≤ health ≤ 1,000
- 1 ≤ attacks의 길이 ≤ 100
- attacks[i]는 [공격 시간, 피해량] 형태의 길이가 2인 정수 배열입니다.
- attacks는 공격 시간을 기준으로 오름차순 정렬된 상태입니다.
- attacks의 공격 시간은 모두 다릅니다.
- 1 ≤ 공격 시간 ≤ 1,000
- 1 ≤ 피해량 ≤ 100
* 입출력 예
분석
- 캐릭터의 생존여부를 판단하고(사망시 -1 ) 남은 체력을 return 한다.
- int[] bandage = {시전시간, 초당회복량, 추가회복량};
- int health = 최대체력;
- int[][] attacks = { {몬스터의 공격시간, 피해량}, {몬스터의 공격시간, 피해량}, ... };
- attacks 를 순환하며 캐릭터의 체력상태를 계속 체크해야 한다.
- 몬스터의 공격시간이 될 경우의 이벤트
(1) 붕대감기를 하지 않음
(2) 붕대감기 연속성공이 0으로 초기화
(3) 몬스터의 공격으로 체력감소 - 몬스터의 공격시간이 아닐 경우의 이벤트
(1) 붕대감기를 함 == bandage[1] 만큼 체력 증진 (최대 체력을 초과하지 않음).
(2) 만약 연속성공횟수가 bangage[0] 와 같아진다면 bandage[2] 만큼 체력 증진 (최대 체력을 초과하지 않음), 그리고 연속성공횟수를 0으로 초기화 - 중간에 체력 <= 0이 되는 상황이 발생하면 그 즉시 -1로 리턴
- 위의 루프가 끝난 후 남은 체력을 return.
- 루프를 어떻게 하는지에 따라서도 로직이 달라질 것 같은데.
- 마지막 몬스터의 공격시간까지 통과하면 루프는 종료된다. 루프의 주체를 시간으로 해서 시간 0 부터 마지막 몬스터의 공격시간까지로 for를 돌려도 됨.
- 혹은 attacks 의 요소를 하나씩 꺼내서 반복하는 경우는 어떨까?
(1) 이렇게 된다면 이전 몬스터의 공격시간부터 지금 몬스터의 공격시간까지 사이에 벌어진 붕대감기와 연속성공이벤트를 별도로 체크해줘야겠지.
(2) [지금 몬스터의 공격시간 - 이전 몬스터의 공격시간] 값을 계산해서 그 사이에 몇 초가 있었는지를 판단한 후, 총 초당 회복 + 연속성공이벤트 회복으로 체력을 증가시킨 후 최대체력을 넘는지만 체크해주면 이번 몬스터의 공격 당시 캐릭터의 체력을 구할 수 있다.
피드백
- 처음엔 루프를 시간(0부터 마지막 몬스터의 공격시간까지)으로 돌리려고 했는데, 막 코드를 짤 때 뭔가 그렇게 짜면 빙 돌아가는 느낌이 들어서 분석 12번으로 쓴 방식으로 코드를 작성했다. 생각보다 막힘없이 잘 짜여져서 만족스럽다.
- 다만 루프문을 어떻게 짤 것인가에 대해 초반에 갈팡질팡하는 과정에서 결과적으로는 쓰이지 않는 쓸모없는 변수를 만들어놓고 제거하지 않았다는 걸 이후에 알고 수정해서, 이후에는 변수들이 모두 제 역할을 하고 있는지 체크할 필요가 있을 듯.
답안
class Solution {
public int solution(int[] bandage, int health, int[][] attacks) {
int answer = health;
int prevAttackTime = 0; // 이전 몬스터의 공격시간
for(int[] attack : attacks) {
// 이전 공격시간 이후의 체력증가 구하기
int timeGap = attack[0] - prevAttackTime - 1;
answer += timeGap * bandage[1]; // 초당 회복력만큼 증가
answer += (timeGap / bandage[0]) * bandage[2]; // 연속성공 추가체력회복 이벤트
if(answer > health) answer = health; // 최대체력 제한조건
answer -= attack[1]; // 몬스터의 공격만큼 체력감소
if(answer <= 0) return -1; // 체력 0 이하일 경우 캐릭터 사망
prevAttackTime = attack[0];
}
return answer;
}
}
다른 사람의 답안
import java.util.*;
class Solution {
public int solution(int[] bandage, int health, int[][] attacks) {
int cnt = bandage[0]; // 추가 체력 기준
int now = health; // 현재 체력
int std = 0; // 마지막으로 공격당한 시간
int v1, v2; // 추가 체력 받을 수 있나?
for (int[] atk: attacks) {
if (now <= 0) {
return -1;
}
v1 = atk[0] - std - 1; // 시간 차이
v2 = v1 / cnt; // 추가 체력 회수
// 맞기 직전까지의 체력 정산
std = atk[0];
now = Math.min(health, now + (v1 * bandage[1]));
now = Math.min(health, now + (v2 * bandage[2]));
now -= atk[1];
}
return now <= 0 ? -1 : now;
}
}
🔗링크
프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr