[프로그래머스] LV1 당구 연습

leewol·2023년 3월 19일
0

코딩테스트

목록 보기
1/1

1) 접근법

점대칭!

혼자 풀어보려고 하다가 결국 시간 더쓰면 안 될듯 해서 (수학적 개념이 분명 있을 거라고 생각했기에..) 질문하기 페이지를 보았는데 힌트가 있었다

참고 블로그

힌트를 참고하여 왼쪽, 오른쪽, 아래쪽, 위쪽에 부딪치는 4가지 경우의 수를 고려해 target좌표의 점대칭 좌표를 구하고, 각 좌표마다의 최소거리 중 최솟값을 정답 배열에 담고자 했다

또한 문제에도 나와 있듯이 머쓱이는 쿠션(공을 쳐서 벽에 맞히는 것)을 원했기에 주어진 예시 케이스처럼 벽에 부딪치지 않는 경우를 고려해야 했다 그래서 상하와 좌우를 세트로 묶어 두 가지 조건으로 나누어 코드를 쓰면 짜잔~ 하고 될 줄 알았으나..

2) 주의사항

x 혹은 y 좌표가 동일할 때 상하 혹은 좌우를 세트로 배제하는 것이 아니다!

  • start ball과 target ball의 x좌표가 동일하면 상, 하 모두를 배제
  • start ball과 target ball의 y좌표가 동일하면 좌, 우 모두를 배제

처음에는 이렇게 접근을 했는데 어라? 실패가 많길래 또 질문하기 참고.. 똑똑하신 분이 친절하게 히든 테스트 케이스와 함께 힌트를 제공해주셨기에 감사한 마음으로 적용했다

직관적으로는 이상하지만 일자로 겹쳐 있는 볼을 아예 칠 수 없다는 조건이 없으니 어쨌든 직선으로 원쿠션이 걸리는 조건을 고려해야 했다

따라서 x좌표가 동일할 때는 start ball의 y좌표 값이 target ball보다 작냐 크냐에 따라 상/하 중에 하나는 최솟값 계산에 포함을 시켰다

(y좌표가 동일할 때도 같은 논리로 좌/우 중에 하나는 포함)

x좌표 동일할 때 예시

  • startY > targetY : 내가 쳐야 하는 공이 더 위에 있으니 up 벽에는 부딪칠 수 있다
  • startY < targetY : 내가 쳐야 하는 공이 더 아래에 있으니 down 벽에는 부딪칠 수 있다

그 결과 다행히도 통과

3) 코드

function solution(m, n, startX, startY, balls) {
    return balls.reduce((answer, ball) => {
        const [targetX, targetY] = ball;
        const targetMaps = {
            left: [-targetX, targetY],
            down: [targetX, -targetY],
            right: [m + (m - targetX), targetY],
            up: [targetX, n + (n - targetY)],
        };
        const targetVals = {
            left: (startX - targetMaps["left"][0]) ** 2 + (startY - targetMaps["left"][1]) ** 2,
            down: (startX - targetMaps["down"][0]) ** 2 + (startY - targetMaps["down"][1]) ** 2,
            right: (startX - targetMaps["right"][0]) ** 2 + (startY - targetMaps["right"][1]) ** 2,
            up: (startX - targetMaps["up"][0]) ** 2 + (startY - targetMaps["up"][1]) ** 2,
        };
        // x축 좌표 동일 - U or D 배제
        if (startX === targetX) {
            if (startY < targetY) return [ ...answer, Math.min(targetVals["left"], targetVals["right"], targetVals["down"])];
            if (startY > targetY) return [ ...answer, Math.min(targetVals["left"], targetVals["right"], targetVals["up"])];
        }
        // y축 좌표 동일 - L or R 배제
        if (startY === targetY) {
            if (startX < targetX) return [ ...answer, Math.min(targetVals["up"], targetVals["down"], targetVals["left"])];
            if (startX > targetX) return [ ...answer, Math.min(targetVals["up"], targetVals["down"], targetVals["right"])];
        }
        return [ ...answer, Math.min(...Object.values(targetVals))];
    }, []);
}
profile
간살간죽 개살개죽

0개의 댓글