프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr
<STUDY>
📢 문제 📢
최근 취미로 알고리즘 문제를 풀기 시작한 당신은,
머쓱이가 친 공이 각각의 목표로한 공에 맞을 때까지 최소 얼마의 거리를 굴러가야 하는지가 궁금해졌습니다.
당구대의 가로 길이 m, 세로 길이 n과 머쓱이가 쳐야 하는 공이 놓인 위치 좌표를 나타내는 두 정수 startX, startY, 그리고 매 회마다 목표로 해야하는 공들의 위치 좌표를 나타내는 정수 쌍들이 들어있는 2차원 정수배열 balls가 주어집니다.
"원쿠션" (당구에서 공을 쳐서 벽에 맞히는 걸 쿠션이라고 부르고, 벽에 한 번 맞힌 후 공에 맞히면 원쿠션이라고 부릅니다) 연습을 위해 머쓱이가 공을 적어도 벽에 한 번은 맞춘 후 목표 공에 맞힌다고 할 때,
각 회마다 머쓱이가 친 공이 굴러간 거리의 최솟값의 제곱을 배열에 담아 return 하도록 solution 함수를 완성해 주세요.
단, 머쓱이가 친 공이 벽에 부딪힐 때 진행 방향은 항상 입사각과 반사각이 동일하며, 만약 꼭짓점에 부딪힐 경우 진입 방향의 반대방향으로 공이 진행됩니다.
공의 크기는 무시하며, 두 공의 좌표가 정확히 일치하는 경우에만 두 공이 서로 맞았다고 판단합니다.
공이 목표 공에 맞기 전에 멈추는 경우는 없으며, 목표 공에 맞으면 바로 멈춘다고 가정합니다.
제한사항
- 3 ≤ m, n ≤ 1,000
- 0 < startX < m
- 0 < startY < n
- 2 ≤ balls의 길이 ≤ 1,000
- balls의 원소는 [a, b] 형태입니다.
- a, b는 머쓱이가 맞춰야 할 공이 놓인 좌표를 의미합니다.
- 0 < a < m, 0 < b < n
- (a, b) = ( startX, startY )인 입력은 들어오지 않습니다.
<전체 코드>
function solution(m, n, startX, startY, balls) {
let answer = [];
balls.forEach(([endX, endY]) => {
let distance = [];
if (startX !== endX || startY > endY) {
distance.push((startX - endX) ** 2 + (startY - 2 * n + endY) ** 2);
}
if (startX !== endX || startY < endY) {
distance.push((startX - endX) ** 2 + (startY + endY) ** 2);
}
if (startY !== endY || startX < endX) {
distance.push((startX + endX) ** 2 + (startY - endY) ** 2);
}
if (startY !== endY || startX > endX) {
distance.push((startX - 2 * m + endX) ** 2 + (startY - endY) ** 2);
}
answer.push(Math.min(...distance));
});
return answer;
}
<풀이 방법>
처음에 문제를 봤을 때 좌표로 풀어야 한다는 감은 잡았지만 정확히 어떤 식으로 풀이를 해야하는지 잘 몰랐다.
그런데 입사각과 반사각이 같고 목표까지 갈 수 있는 최단거리를 구한다는 말에서
아래 그림과 같이 목표 좌표(공)를 대칭을 시키면 거리를 알 수 있다는 것을 깨달았다.
그러나 x좌표가 같거나 y좌표가 같은 경우 아래 그림처럼 쿠션에 부딪히기 전에 목표 좌표(공)과 먼저 부딪히기 때문에 불가능한 경우가 생긴다.
👻 부딪히는 경우
- x1 === x2 이고 y1 < y2 : 위쪽 대칭 (y = n)
- x1 === x2 이고 y1 > y2 : 아래쪽 대칭 (x축)
- y1 === y2 이고 x1 < x2 : 오른쪽 대칭 (x = m)
- y1 === y2 이고 x1 > x2 : 왼쪽 대칭 (y축)
이 경우를 고려하여 x축, y축, x = m, y = n을 기준으로 대칭시켜 그 중 가장 짧은 길이를 선택한다.
if (startX !== endX || startY > endY) {
distance.push((startX - endX) ** 2 + (startY - 2 * n + endY) ** 2);
}
if (startX !== endX || startY < endY) {
distance.push((startX - endX) ** 2 + (startY + endY) ** 2);
}
if (startY !== endY || startX < endX) {
distance.push((startX + endX) ** 2 + (startY - endY) ** 2);
}
if (startY !== endY || startX > endX) {
distance.push((startX - 2 * m + endX) ** 2 + (startY - endY) ** 2);
}
answer.push(Math.min(...distance));
처음에 대칭을 한다는 생각을 하지 못해서 생각보다 오래걸렸다.
어떤 방법으로 풀어야 하는지 큰 그림을 먼저 그리고 알고리즘을 생각하는 연습이 필요할 것 같다.
앞으로 더 열심히 해야겠다!
🔆프로그래머스 Lv2. 당구 연습🔆
ez1n - Overview
Front-End Developer. ez1n has 18 repositories available. Follow their code on GitHub.
github.com
'STUDY > Algorithm' 카테고리의 다른 글
탐색 알고리즘 (Search Algorithm) / 선형 탐색, 이진 탐색 (0) | 2023.04.02 |
---|---|
재귀함수 (Recursion Function) / JS (2) | 2023.04.01 |
[프로그래머스_자바스크립트] Lv.1 포켓몬 / 해시 (Hash) (0) | 2023.01.26 |
[프로그래머스_자바스크립트] Lv.1 숫자 짝꿍 / 해시 알고리즘 (0) | 2023.01.23 |
[프로그래머스_자바스크립트] Lv.1 햄버거 만들기 (0) | 2023.01.22 |