본문 바로가기

코딩 테스트(Coding Test)/이것이 코딩 테스트다

문제 07) 방문 길이

게임 캐릭터를 4가지 명령어를 통해 움직이려 합니다. 명령어는 다음과 같습니다.

  • U : 위쪽으로 한 칸
  • D : 아래쪽으로 한 칸
  • R : 오른쪽으로 한 칸
  • L : 왼쪽으로 한 칸

캐릭터는 좌표평면의 (0, 0) 위치에서 시작합니다. 좌표평면의 경계는 왼쪽 위(-5, 5), 왼쪽 아래(-5, -5), 오른쪽 위(5, 5), 오른쪽 아래(5, -5)로 구성합니다.

 

이때 우리는 게임 캐리거가 지나간 길 중 캐릭터가 처음 걸어본 길의 길이를 구하려고 합니다. 명령어가 매개변수 dirs로 주어질 때 게임 캐릭터가 처음 걸어본 길의 길이를 구해 반환하는 solution() 함수를 완성하세요.


제약조건

  • dirs는 string형으로 주어지며, 'U', 'D', 'R', 'L' 이외의 문자는 주어지지 않습니다.
  • dirs의 길이는 500자 이하의 자연수입니다.

입출력의 예

dirs answer
ULURRDLLU 7
LULLLLLLU 7

아이디어 - (오답)

위 문제를 풀면서 시간 복잡도를 고려하다보니, 2차원 배열 탐색을 이중 for문을 사용하면 O(n^2)의 복잡도를 가질것 같았다.

그래서 먼저 1차원 배열로 생각해보았다.

 

어차피 범위는 x, y 좌표 모두 -5 ~ 5 까지이니, 왼쪽 최하단 점인(-5, -5)를 0번째 인덱스 / 우측 최상단 점인 (5, 5)를 120번째 인덱스로 생각하여 boolean[] visited = new boolean[121]의 1차원 배열을 선언했다. 그리하여 원점은 visted[60]번째 인덱스를 true로 표현.

각각

'U' : +11

'D' : -11

'L' : -1

'R' : +1

로 생각하여 문제를 해결해나갔다. 그리하여 방문하지 않은 점일 때마다 count하여 답을 반환했는데, 문제가 발생했다.

한번 방문했다고 카운트 하지 않는 것이 아니라, 다른 길로 돌아오는 경우에는 카운트 해야 하는데, 아예 점 자체를 건너뛰어버려 정확한 답이 나오지 않았다. 아래 코드는 기록해두고 다른 방법을 찾아보겠다.

 

[오답 코드]

private static int solution(String dirs){
        boolean[] visted = new boolean[121];
        int point = 60; // 원점
        int count = 0;
        visted[point] = true;

        for(int i=0; i<dirs.length(); i++){
            char c = dirs.charAt(i);
            switch(c){
                case 'U':
                    point += 11;
                    break;

                case 'D':
                    point -= 11;
                    break;

                case 'L':
                    point -= 1;
                    break;

                case 'R':
                    point += 1;
                    break;
            }
            if(!visted[point]){
                count++;
                visted[point] = true;
            }
        }

        return count;
    }

정답 코드

이중 for문이 아닌, HashMap을 사용하면 O(n^2)의 시간 복잡도가 아니라, O(N)의 복잡도로도 충분히 구현이 가능했다.

// 좌표 평면을 벗어나는지
    private static boolean isValidMove(int nx, int ny){
        return 0 <= nx && nx < 11 && 0 <= ny && ny < 11;
    }

    // 다음 좌표  결정을 위한 해시맵
    private static final HashMap<Character, int[]> location = new HashMap<>();

    private static void initLocation(){
        location.put('U', new int[]{0,1});
        location.put('D', new int[]{0,-1});
        location.put('L', new int[]{-1,0});
        location.put('R', new int[]{1,0});
    }

    private static int solution(String dirs){
        initLocation();

        int x = 5, y = 5;
        HashSet<String> answer = new HashSet<>(); // 겹치는 좌표는 1개로 처리

        for(int i=0; i<dirs.length(); i++){
            int[] offset = location.get(dirs.charAt(i));
            int nx = x + offset[0];
            int ny = y + offset[1];
            if(!isValidMove(nx, ny)){
                continue;
            }

            answer.add(x + " " + y + " " + nx + " " + ny);
            answer.add(nx + " " + ny + " " + x + " " + y);

            x = nx;
            y = ny;
        }

        return answer.size() / 2;
    }