본문 바로가기

Algorithm/level2

[ 프로그래머스 - Java & Kotlin ] [ 1차 ] 프렌즈4블록 ( 자바 & 코틀린 )

728x90

( 2018 KAKAO BLIND RECRUITMENT / [1차] 프렌즈4블록 )

[문제]

문제 설명

블라인드 공채를 통과한 신입 사원 라이언은 신규 게임 개발 업무를 맡게 되었다. 이번에 출시할 게임 제목은 "프렌즈4블록".
같은 모양의 카카오프렌즈 블록이 2×2 형태로 4개가 붙어있을 경우 사라지면서 점수를 얻는 게임이다.


만약 판이 위와 같이 주어질 경우, 라이언이 2×2로 배치된 7개 블록과 콘이 2×2로 배치된 4개 블록이 지워진다. 같은 블록은 여러 2×2에 포함될 수 있으며, 지워지는 조건에 만족하는 2×2 모양이 여러 개 있다면 한꺼번에 지워진다.

블록이 지워진 후에 위에 있는 블록이 아래로 떨어져 빈 공간을 채우게 된다.

만약 빈 공간을 채운 후에 다시 2×2 형태로 같은 모양의 블록이 모이면 다시 지워지고 떨어지고를 반복하게 된다.

위 초기 배치를 문자로 표시하면 아래와 같다.

TTTANT
RRFACC
RRRFCC
TRRRAA
TTMMMF
TMMTTJ

각 문자는 라이언(R), 무지(M), 어피치(A), 프로도(F), 네오(N), 튜브(T), 제이지(J), 콘(C)을 의미한다

입력으로 블록의 첫 배치가 주어졌을 때, 지워지는 블록은 모두 몇 개인지 판단하는 프로그램을 제작하라.

입력 형식

  • 입력으로 판의 높이 m, 폭 n과 판의 배치 정보 board가 들어온다.
  • 2 ≦ n, m ≦ 30
  • board는 길이 n인 문자열 m개의 배열로 주어진다. 블록을 나타내는 문자는 대문자 A에서 Z가 사용된다.

출력 형식

입력으로 주어진 판 정보를 가지고 몇 개의 블록이 지워질지 출력하라.

입출력 예시

m n board answer
4 5 ["CCBDE", "AAADE", "AAABF", "CCBBF"] 14
6 6 ["TTTANT", "RRFACC", "RRRFCC", "TRRRAA", "TTMMMF", "TMMTTJ"] 15
  • 입출력 예제 1의 경우, 첫 번째에는 A 블록 6개가 지워지고, 두 번째에는 B 블록 4개와 C 블록 4개가 지워져, 모두 14개의 블록이 지워진다.
  • 입출력 예제 2는 본문 설명에 있는 그림을 옮긴 것이다. 11개와 4개의 블록이 차례로 지워지며, 모두 15개의 블록이 지워진다.

[풀이]

차근차근 주어진 조건대로 함수를 구성하여 구현해 나가면 풀 수 있는 문제입니다.

보드에서 지워야 할 항목이 있는지 체크하는 함수(checkBoard), 지워야 할 항목들을 표시해주는 함수(checkItem), 항목을 지운 뒤에 아래쪽으로 배열을 재구성해 주는 함수(dropBoard) 이렇게 3가지를 구현 후 지워야 할 항목이 없을 때까지 반복을 해주면 됩니다. 자세한 내용은 아래 코드 주석에서 확인해주세요~


[코드]

자바

class Solution {
    public int solution(int m, int n, String[] board) {
        int answer = 0;
        char[][] arr = new char[m][n];
        // 2차원 배열로 변환
        for(int i = 0; i < board.length; i++)
            arr[i] = board[i].toCharArray();
        
        while(true){
            // 지워야 할 항목의 개수를 체크
            int cnt = checkBoard(arr, m, n);
            // 지워야 할 항목이 없다면 중단
            if(cnt == 0) break;
            // 지워야 할 항목을 answer에 누적 합
            answer += cnt;
            // 보드에서 공백인 부분 위에 항목으로 채우기
            dropBoard(arr, m, n);
        }
        
        return answer;
    }
    
    public int checkBoard(char[][] arr, int m, int n){
        // 현재 상태에서의 공백인 부분을 구분하기 위함 boolean2차원 배열
        boolean[][] check = new boolean[m][n];
        // 공백인 부분 카운트
        int cnt = 0;
        // i행 i+1행까지와 j열 j+1열까지를 비교하기 위해 각각 m-1, n-1까지 반복 진행
        for(int i = 0; i < m - 1; i++){
            for(int j = 0; j < n - 1; j++){
                // 공백인 아닌경우 해당 칸 주변의 항목이 지워도 되는 항목인지 체크
                if(arr[i][j] != ' ') checkItem(arr, check, i, j);
            }
        }
        
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                // 지워야 할 항목이 있을 경우 공백으로 치환 후 cnt증가
                if(check[i][j]) {
                    arr[i][j] = ' ';
                    cnt++;
                }
            }
        }
        
        return cnt;
    }
    
    public void checkItem(char[][] arr, boolean[][] check, int i, int j){
        // i행 i+1행까지와 j열 j+1열까지 다른 항목이 있을경우 checkItem중단
        for(int y = i; y < i + 2; y++){
            for(int x = j; x < j + 2; x++){
                if(arr[i][j] != arr[y][x]) return;
            }
        }
        // i행 i+1행까지와 j열 j+1열까지 항목은 지워도 되는 항목임으로 해당 범위 전부 check를 true로 초기화
        for(int y = i; y < i + 2; y++){
            for(int x = j; x < j + 2; x++){
                check[y][x] = true;
            }
        }
    }
    
    public void dropBoard(char[][] arr, int m, int n){
        for(int j = 0; j < n; j++){
            for(int i = m - 1; i >= 0; i--){
                // 공백일 경우부터 그다음 항목이 공백이 아닌 값과 swap후 반복 종료 (중간에 공백인 항목을 지우기 위함)
                if(arr[i][j] == ' '){
                    for(int k = i - 1; k >= 0; k--){
                        if(arr[k][j] != ' '){
                            arr[i][j] = arr[k][j];
                            arr[k][j] = ' ';
                            break;
                        }
                    }
                }
            }
        }
    }
}

코틀린

fun solution(m:Int, n:Int, board:Array<String>):Int{
    var answer = 0
    // 2차원 배열로 변환
    val arr = Array<CharArray>(m){ board[it].toCharArray() }

    while(true){
        // 지워야 할 항목의 개수를 체크
        val cnt = checkBoard(arr, m, n)
        // 지워야 할 항목이 없다면 중단
        if(cnt == 0) break
        // 지워야 할 항목을 answer에 누적 합
        answer += cnt
        // 보드에서 공백인 부분 위에 항목으로 채우기
        dropBoard(arr, m, n)
    }

    return answer
}

fun checkBoard(arr:Array<CharArray>, m:Int, n:Int):Int{
    // 현재 상태에서의 공백인 부분을 구분하기 위함 boolean2차원 배열
    val check = Array<BooleanArray>(m){BooleanArray(n)}
    // 공백인 부분 카운트
    var cnt = 0

    // i행 i+1행까지와 j열 j+1열까지를 비교하기 위해 각각 m-1, n-1까지 반복 진행
    for(i in 0 until m - 1){
        for(j in 0 until n - 1){
            // 공백인 아닌경우 해당 칸 주변의 항목이 지워도 되는 항목인지 체크
            if(arr[i][j] != ' ') checkItem(arr, check, i, j)
        }
    }
    for(i in 0 until m){
        for(j in 0 until n){
            // 지워야 할 항목이 있을 경우 공백으로 치환 후 cnt증가
            if(check[i][j]){
                arr[i][j] = ' '
                cnt++
            }
        }
    }

    return cnt
}

fun checkItem(arr:Array<CharArray>, check:Array<BooleanArray>, i:Int, j:Int){
    // i행 i+1행까지와 j열 j+1열까지 다른 항목이 있을경우 checkItem중단
    for(y in i until i + 2){
        for(x in j until j + 2){
            if(arr[i][j] != arr[y][x]) return
        }
    }
    // i행 i+1행까지와 j열 j+1열까지 항목은 지워도 되는 항목임으로 해당 범위 전부 check를 true로 초기화
    for(y in i until i + 2){
        for(x in j until j + 2){
            check[y][x] = true
        }
    }
}

fun dropBoard(arr:Array<CharArray>, m:Int, n:Int){
    for(j in 0 until n){
        for(i in m - 1 downTo 0){
            // 공백일 경우부터 그다음 항목이 공백이 아닌 값과 swap후 반복 종료 (중간에 공백인 항목을 지우기 위함)
            if(arr[i][j] == ' '){
                for(k in i - 1 downTo 0){
                    if(arr[k][j] != ' ') {
                        arr[i][j] = arr[k][j].also { arr[k][j] = arr[i][j] }
                        break
                    }
                }
            }
        }
    }
}

문제 링크

 

코딩테스트 연습 - [1차] 프렌즈4블록

프렌즈4블록 블라인드 공채를 통과한 신입 사원 라이언은 신규 게임 개발 업무를 맡게 되었다. 이번에 출시할 게임 제목은 "프렌즈4블록". 같은 모양의 카카오프렌즈 블록이 2×2 형태로 4개가 붙

programmers.co.kr

제가 잘못 알고 있거나 잘못된 부분이 있을 경우 알려주시고 추가로 궁금한 점 있으신 분들도 댓글이나 메일 주시면 성실히 답변해 드리겠습니다.🧑🏻‍💻

감사합니다~😄

728x90