KO EN

[Kotlin] 프로그래머스 - 단체 사진 찍기

by 민갤

Back End /

문제

링크

가을을 맞아 카카오프렌즈는 단체로 소풍을 떠났다. 즐거운 시간을 보내고 마지막에 단체사진을 찍기 위해 카메라 앞에 일렬로 나란히 섰다. 그런데 각자가 원하는 배치가 모두 달라 어떤 순서로 설지 정하는데 시간이 오래 걸렸다. 네오는 프로도와 나란히 서기를 원했고, 튜브가 뿜은 불을 맞은 적이 있던 라이언은 튜브에게서 적어도 세 칸 이상 떨어져서 서기를 원했다. 사진을 찍고 나서 돌아오는 길에, 무지는 모두가 원하는 조건을 만족하면서도 다르게 서는 방법이 있지 않았을까 생각해보게 되었다. 각 프렌즈가 원하는 조건을 입력으로 받았을 때 모든 조건을 만족할 수 있도록 서는 경우의 수를 계산하는 프로그램을 작성해보자.

입력은 조건의 개수를 나타내는 정수 n과 n개의 원소로 구성된 문자열 배열 data로 주어진다. data의 원소는 각 프렌즈가 원하는 조건이 N~F=0과 같은 형태의 문자열로 구성되어 있다.

제한사항

1 <= n <= 100

data의 원소는 다섯 글자로 구성된 문자열이다. 각 원소의 조건은 다음과 같다.

  • 첫 번째 글자와 세 번째 글자는 다음 8개 중 하나이다. {A, C, F, J, M, N, R, T} 각각 어피치, 콘, 프로도, 제이지, 무지, 네오, 라이언, 튜브를 의미한다. 첫 번째 글자는 조건을 제시한 프렌즈, 세 번째 글자는 상대방이다. 첫 번째 글자와 세 번째 글자는 항상 다르다.
  • 두 번째 글자는 항상 ~이다.
  • 네 번째 글자는 다음 3개 중 하나이다. {=, <, >} 각각 같음, 미만, 초과를 의미한다.
  • 다섯 번째 글자는 0이상 6이하의 정수의 문자형이며, 조건에 제시되는 간격을 의미한다. 이때 간격은 두 프렌즈 사이에 있는 다른 프렌즈의 수이다.

입출력 예시

입출력 예 #1

  • 입력
  • n: 2
  • data: ["N~F=0", "R~T>2"]
  • 출력: 3648

입출력 예 #2

  • 입력
  • n: 2
  • ["M~C<2", "C~M>1"]
  • 출력: 0

풀이

대상 8개를 정렬하는 방법을 구하므로 순열(Permutation) 문제이다.

입력 조건수가 최대 100개이고, 대상 8개를 정렬하는 모든 경우의 수(8!)가 크기 않기 때문에 완전 탐색(Exhaustive Search)을 이용한다.

코드. Kotlin

class Solution {
    private val friends = "ACFJMNRT"
    private var answer = 0

    private fun solution(n: Int, data: Array<String>): Int {
        permutation(
            depth = 0,
            alignedFriends = Array(friends.length) { '_' },
            visited = Array(friends.length) { false },
            conditions = data
        )
        return answer
    }

    /**
     * 순열
     * - 서로 다른 n개의 원소에서 r개를 중복없이 골라 순서에 상관있게 나열한다.
     *
     * @param depth: 깊이
     * @param alignedFriends: 정렬된 친구들
     * @param visited: 방문 여부
     * @param conditions:  조건
     */
    private fun permutation(
        depth: Int,
        alignedFriends: Array<Char>,
        visited: Array<Boolean>,
        conditions: Array<String>
    ) {
        // 순열 처리가 끝나면 조건을 만족하는지 확인
        if (depth == friends.length) {
            if (check(conditions, alignedFriends)) answer++
            return
        }
        // 순열 처리
        for (i in friends.indices) {
            if (visited[i]) continue

            alignedFriends[depth] = friends[i]
            visited[i] = true
            permutation(depth + 1, alignedFriends, visited, conditions)
            visited[i] = false
        }
    }

    /**
     * 조건을 만족하는 지 확인
     */
    private fun check(conditions: Array<String>, alignedFriends: Array<Char>): Boolean {
        conditions.forEach { condition ->
            val from = alignedFriends.indexOf(condition[0])
            val to = alignedFriends.indexOf(condition[2])
            val diff = abs(from - to)
            val interval = condition[4].toString().toInt() + 1
            when (condition[3]) {
                '>' -> if (diff <= interval) return false
                '<' -> if (diff >= interval) return false
                '=' -> if (diff != interval) return false
            }
        }
        return true
    }
}
Kotlin 제출 없음. 입출력 예시 2개 통과

코드. JAVA

class Solution {
    private String[] friends = {"A", "C", "F", "J", "M", "N", "R", "T"};
    private boolean[] visited;

    private int answer = 0;
        
    public int solution(int n, String[] data) {
        visited = new boolean[8];

        permutation("", data);

        return answer;
    }
    
    private void permutation(String alignedFriends, String[] conditions) {
        if (alignedFriends.length() == friends.length) {
            if (check(alignedFriends, conditions)) answer++;
            return;
        }
        for (int i = 0; i < friends.length; i++) {
            if (visited[i]) continue;

            visited[i] = true;
            permutation(alignedFriends + friends[i], conditions);
            visited[i] = false;
        }
    }

    private boolean check(String alignedFriends, String[] conditions) {
        for (String condition: conditions) {
            int start = alignedFriends.indexOf(condition.charAt(0));
            int end = alignedFriends.indexOf(condition.charAt(2));
            
            int diff = Math.abs(start - end);
            int interval = condition.charAt(4) - '0' + 1;
            
            char inequality = condition.charAt(3);
            if (inequality == '>') {
                if (diff > interval) continue;
            } else if (inequality == '<') {
                if (diff < interval) continue;
            } else if (inequality == '=') {
                if (diff == interval) continue;
            }
            return false;
        }
        return true;
    }
}
테스트 1 〉	통과 (1542.16ms, 378MB)

Kotlin 전체 코드 링크

Author

민갤

민갤

Back-End Developer

꾸잉꾸잉하고 웁니다.

로그인

디코에 오신 것을 환영해요!
전문가들의 수많은 아티클 창고 🤓