<프로그래머스> 행렬 테두리 회전하기(Lv.2)
[깃허브]
[프로그래머스]
https://school.programmers.co.kr/learn/courses/30/lessons/77485
행렬 크기 제한이 작아서 다행이라고 생각했던 문제였다.
'지금보다 훨씬 컸다면 다른 방법을 생각해내야하지 않았을까?'라는 생각이 다 풀고 나서 들었다.
문제는 금방 이해했다.
주어지는 범위의 테두리값들을 오른쪽으로 한칸씩 회전시키고 그 중에 가장 작은 값을 뽑으면 되는 거다.
처음에 문제를 보고 '그냥 회전 안 시키고 테두리값만 가져와서 가장 작은 값 가져오면 되지 않나?'라고 생각을 했지만 회전을 여러번 진행하기 때문에 이 생각은 기각처리되었다.
가장 먼저 만난거는 2차원 배열 초기화였다.
기존에 하는 방식대로라면 0으로 모두 초기화한 다음에 반복문을 통해서 값을 1부터 넣어줬을 거다.
하지만 오늘 새로운 방식을 알았다.
이건 앞으로도 유용하게 쓸 수 있지 않을까 싶다.
var matrix = Array<IntArray>(rows) { i -> IntArray(columns) { j -> i * columns + j + 1} }
지금 몇 번째 row인지 알려주는 i와 몇 번째 col인지 알려주는 j를 통해 좌표마다 들어갈 값을 연산을 통해 초기화한다.
이런 좋은 방법이 있었다니... 이제는 기억했다.
다음으로는 어떻게 회전을 시킬 것인지 고민하는 단계였다.
이리저리 만져보다가 한 문제가 생각났다.
바로 삼각 달팽이 문제였다. (링크 : https://retry-thinksubox.tistory.com/79 )
여기서는 회전이 아니라 숫자를 채워넣는 문제였지만 내가 지금 필요한 구조를 사용하고 있었다.
그래서 이 구조를 가져왔다.
오른쪽, 아래쪽, 왼쪽, 위쪽에 대한 Boolean 변수를 선언하고 주어진 범위에 마지막에 닿을때마다 방향을 바꾸도록 했다.
한바퀴만 돌면 되기 때문에 마지막 위쪽 방향에서는 반복문을 탈출할 수 있게 했다.
구조는 이제 준비가 다 됐고 이제 값을 채워넣는 것만 남았는데 여기가 제일 오래 걸렸다.
가장 먼저는 x, y가 헷갈렸다.
현실에서는 위아래가 y고 좌우가 x인데 배열에서는 위아래가 x고 좌우가 y라서 이걸 정리하는게 헷갈리더라...
그래도 문제에 주어진대로 진행을 했고 값을 회전시켰다.
그리고 실행을 해보니 범위의 테두리값이 모두 하나의 값으로 통일되었다!!! 야호~
이거는x와 y 값을 계속 변경시켰다고 생각했는데 디버깅을 해보니까 다음 값이 이전 값에 덮여써져서 남아있지 않기 때문에 일어나는 문제였다.
'배열을 하나더 만들어야되나...'라는 무서운 생각이 들었지만 차분히 마음을 가라앉혔다.
다음으로 든 생각은 swap이었다.
하지만 이건 두 수를 바꾸는 거지 회전을 위해 다음 값으로 계속 넘겨주는거에는 어울리지 않았다.
그래서 최종적으로 선택한 방법은 2개의 temp 변수를 만드는 것이었다.
하나는 prev로 이전 값을 저장하고, 하나는 cur로 현재 값을 저장한다.
값을 변경할 때에 현재 값을 이전 값에 넣고, 현재값에 덮여써질 위치의 값을 넣고, 덮여써지는 위치에는 이전 값을 넣으면 된다.
말로보면 이상한데 코드를 보면 이해가 될 것이다.
swap에서 temp를 이용하는 것을 약간 응용했다고 보면 된다.
해당 방법으로 작성한 코드는 다음과 같다.
class Solution {
fun solution(rows: Int, columns: Int, queries: Array<IntArray>): IntArray {
var answer = intArrayOf()
// 2차원 행렬(1..rows*columns)
var matrix = Array<IntArray>(rows) { i -> IntArray(columns) { j -> i * columns + j + 1} }
for (query in queries) {
// 테두리값 저장하는 리스트
var numList = intArrayOf()
// 반복문 탈출 여부 변수
var isClear = false
var x = query[0] - 1
var y = query[1] - 1
// 이전 값 저장
var prev = 0
// 현재 값 저장
var cur = matrix[x][y]
// 방향 지정 변수(처음에는 오른쪽으로 진행)
var isLeft = false
var isRight = true
var isDown = false
var isUp = false
while (!isClear) {
when {
// 왼쪽 방향으로 갈 때
isLeft -> {
if (y > query[1] - 1) {
prev = cur
cur = matrix[x][y - 1]
matrix[x][y - 1] = prev
numList += prev
y--
} else {
prev = cur
cur = matrix[x - 1][y]
matrix[x - 1][y] = prev
numList += prev
x--
// 방향 변경
isLeft = false
isUp = true
}
}
// 오른쪽 방향으로 갈 때
isRight -> {
if (y < query[3] - 1) {
prev = cur
cur = matrix[x][y + 1]
matrix[x][y + 1] = prev
numList += prev
y++
} else {
prev = cur
cur = matrix[x + 1][y]
matrix[x + 1][y] = prev
numList += prev
x++
// 방향 변경
isRight = false
isDown = true
}
}
// 아래쪽 방향으로 갈 때
isDown -> {
if (x < query[2] - 1) {
prev = cur
cur = matrix[x + 1][y]
matrix[x + 1][y] = prev
numList += prev
x++
} else {
prev = cur
cur = matrix[x][y - 1]
matrix[x][y - 1] = prev
numList += prev
y--
// 방향 변경
isDown = false
isLeft = true
}
}
// 위쪽 방향으로 갈 때
isUp -> {
if (x > query[0] - 1) {
prev = cur
cur = matrix[x - 1][y]
matrix[x - 1][y] = prev
numList += prev
x--
} else {
// 반복문 종료
isUp = false
isClear = true
}
}
}
}
// 가장 작은 값 answer에 저장
answer += numList.minOf { it }
}
return answer
}
}
이 문제를 풀면서 디버깅을 해보는게 중요하다는 걸 느꼈다.
이번에는 따로 실패 코드를 깃허브에 올리지 않았는데 그건 디버깅에서 실패 요소들을 다 잡고 제출했기 때문이다.
그게 아니었으면 이번에도 한 3개정도의 실패 코드가 깃허브에 올라가지 않았을까 싶다.
범위, 덮어쓰기, 변수증감 다 한번씩 걸렸으니까...