100세까지 코딩
[프로그래머스] Lv0.정수를 나선형으로 배치하기 본문
문제 설명
풀기 전 생각
- 반복문을 돌려 cnt가 n*n개가 되면 반복을 멈추기
- 나선형이니 오른쪽 -> 아래쪽 -> 왼쪽 -> 위쪽을 반복하기
- if문을 방향마다 나눠서 그 방향으로 계속 진행하는 반복문을 실행
- 반복문을 실행하다가 끝지점에 왔거나 진행 방향의 다음칸이 0 이 아닌 다른 숫자가 이미 있으면 방향 전환
class Solution {
public int[][] solution(int n) {
int[][] answer = new int[n][n]; // n X n 크기의 배열 생성
int cnt = 0; // 갯수
int direction = 1; // 방향 1: 오른쪽, 2: 아래쪽, 3: 왼쪽, 4: 위쪽
int x = 0; // 행
int y = 0; // 열
while(cnt < n*n){
if(direction == 1) { // 오른쪽
while(y < n){ // 끝에 도달하기 전까지
if(answer[x][y] != 0){ // 지금 자리가 0이 아닌 수가 있으면
direction = 2; // 아래쪽으로 방향 전환
break;
}
answer[x][y] = ++cnt; // 숫자 늘려주기
y++; // 오른쪽으로 열 이동
}
}
else if(direction == 2) { // 아래쪽
while(x < n){ // 끝에 도달하기 전까지
if(answer[x][y-1] != 0){ // 그 다음 자리 확인
direction = 3; // 왼쪽
break;
}
answer[x][y-1] = ++cnt;
x++; // 아래쪽으로 행 이동
}
}
else if(direction == 3) { // 왼쪽
while(y >= 0){
if(answer[x-1][y] != 0){
direction = 4; // 위쪽
break;
}
answer[x-1][y] = ++cnt;
y--; // 왼쪽으로 열 이동
}
}
else if(direction == 4) { // 위쪽
while(x >= 0){
if(answer[x-1][y] != 0){
direction = 1; // 오른쪽으로 다시
break;
}
answer[x][y] = ++cnt;
x--; // 위쪽으로 행 이동
}
}
}
return answer;
}
}
오류 및 개선
- ArrayIndexOutOfBoundsException 오류가 뜸
- 첫 바퀴는 나선형으로 돌아가다가 그다음 바퀴부턴 진행 방향 다음을 확인하기가 어려움
- 너무 알고리즘이 없는 노가다식 코드라는 것을 느낌
- ArrayIndexOutOfBoundsException를 보고 try-catch를 써보기로 결정
- try안에 반복문을 계속 실행해서 다음 방향 숫자가 0이 아니면 방향 전환 & 다음 칸에 위치시켜 주고 break,
ArrayIndexOutOfBoundsException 오류가 나면 catch에서 방향 전환 & 다음 칸에 위치시켜 주기 - 방향을 숫자 말고 가독성 있게 동서남북 NSWE로 표기
최종
class Solution {
public int[][] solution(int n) {
int[][] answer = new int[n][n]; // n X n 크기의 배열 생성
int cnt = 0; // 개수
char direction = 'E'; // 방향 'N' 'S' 'W' 'E'
int x = 0; // 행
int y = 0; // 열
while (cnt < n * n ) {
if (direction == 'E') { // 오른쪽
try {
while (true) {
if (answer[x][y] != 0) { // 지금 자리가 0이 아닌 수가 있으면
x++; // 아래로 한칸
y--; // 왼쪽으로 한칸
direction = 'S'; // 방향은 아래로
break;
}
answer[x][y++] = ++cnt;
}
} catch (ArrayIndexOutOfBoundsException e) {
x++; // 위와 동일
y--;
direction = 'S';
}
} else if (direction == 'S') { // 아래쪽
try {
while (true) {
if (answer[x][y] != 0) {
x--; // 위로 한칸
y--; // 왼쪽으로 한칸
direction = 'W'; // 방향은 왼쪽으로
break;
}
answer[x++][y] = ++cnt;
}
} catch (ArrayIndexOutOfBoundsException e) {
x--;
y--;
direction = 'W';
}
} else if (direction == 'W') { // 왼쪽
try {
while (true) {
if (answer[x][y] != 0) {
x--; // 위로 한칸
y++; // 오른쪽으로 한칸
direction = 'N'; // 방향은 위쪽으로
break;
}
answer[x][y--] = ++cnt;
}
} catch (ArrayIndexOutOfBoundsException e) {
x--;
y++;
direction = 'N';
}
} else if (direction == 'N') { // 위쪽
try {
while (true) {
if (answer[x][y] != 0) {
x++; // 아래로 한칸
y++; // 오른쪽으로 한칸
direction = 'E'; // 방향은 오른쪽으로 다시 반복
break;
}
answer[x--][y] = ++cnt;
}
} catch (ArrayIndexOutOfBoundsException e) {
x++;
y++;
direction = 'E';
}
}
}
return answer;
}
}
베스트 코드
class Solution {
public int[][] solution(int n) {
int[][] answer = new int[n][n];
int num = 1;
int x = 0, y = 0;
int dx[] = {0, 1, 0, -1}; // 0 : 오른쪽 1 : 아래쪽 2 : 왼쪽 3 : 위쪽
int dy[] = {1, 0, -1, 0};
int direction = 0; // 0 : 오른쪽 1 : 아래쪽 2 : 왼쪽 3 : 위쪽
while (num <= n * n) {
answer[x][y] = num++;
int nx = x + dx[direction]; // 원래의 x값 + 방향
int ny = y + dy[direction]; // 원래의 y값 + 방향
if (nx < 0 || nx >= n || ny < 0 || ny >= n || answer[nx][ny] != 0) { // 끝지점 or 이미 숫자가 있으면
direction = (direction + 1) % 4; // 방향 전환 0,1,2,3 반복
nx = x + dx[direction]; // 원래의 x값 + 방향
ny = y + dy[direction]; // 원래의 y값 + 방향
}
x = nx;
y = ny;
}
return answer;
}
}
참고
지금부터 코딩 실력을 올리고자 깔끔하고 성능 좋은 코드도 함께 포스팅할 예정이다
오류처리도 공부해 두자!!
'코딩테스트 > 자바' 카테고리의 다른 글
[프로그래머스] Lv0.배열 조각하기 (0) | 2023.08.27 |
---|---|
[프로그래머스] Lv0.주사위 게임 (0) | 2023.08.26 |
[프로그래머스] Lv0.OX퀴즈 (0) | 2023.08.18 |
[프로그래머스] Lv0.유한소수 판별하기 (0) | 2023.08.18 |
[프로그래머스] Lv0.최빈값 구하기 (0) | 2023.08.17 |