관리 메뉴

100세까지 코딩

[프로그래머스] Lv0.정수를 나선형으로 배치하기 본문

코딩테스트/자바

[프로그래머스] Lv0.정수를 나선형으로 배치하기

100세까지 코딩 2023. 8. 25. 21:47
문제 설명

 

풀기 전 생각
  • 반복문을 돌려 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;
    }
}
참고
지금부터 코딩 실력을 올리고자 깔끔하고 성능 좋은 코드도 함께 포스팅할 예정이다
오류처리도 공부해 두자!!