본문 바로가기

알고리즘/카카오

프렌즈4블록

반응형

https://programmers.co.kr/learn/courses/30/lessons/17679

 

코딩테스트 연습 - [1차] 프렌즈4블록 | 프로그래머스

프렌즈4블록 블라인드 공채를 통과한 신입 사원 라이언은 신규 게임 개발 업무를 맡게 되었다. 이번에 출시할 게임 제목은 프렌즈4블록. 같은 모양의 카카오프렌즈 블록이 2×2 형태로 4개가 붙어있을 경우 사라지면서 점수를 얻는 게임이다. 만약 판이 위와 같이 주어질 경우, 라이언이 2×2로 배치된 7개 블록과 콘이 2×2로 배치된 4개 블록이 지워진다. 같은 블록은 여러 2×2에 포함될 수 있으며, 지워지는 조건에 만족하는 2×2 모양이 여러 개 있다면

programmers.co.kr


카카오의 코딩테스트를 풀면서 한 문제에 여러가지 로직이 들어간다고 생각했습니다. 그래서 한 부분에서 꼬이게 되면 계속 꼬여서 처음부터 풀이를 잘 생각하고 체계적으로 풀어야 하는 것 같습니다. 이번 문제에서도 설명을 따라서 하나하나씩 코드를 실수 없이 풀어가다보면 해결할 수 있었습니다. 저는 어려웠던 부분이 4블록을 찾아 표시하는 것 까지는 했지만, 이제 그 블록들을 없애고 열 단위로 위에서 비어있는 칸에 당겨서 채워가는 부분이 어려웠습니다. 그래서 저는 열이 n개로 주워져있기 때문에 n개의 ArrayList를 만들어서 반복할 때 마다 없앤 칸을 제외하고 ArrayList 에 넣어서 새로운 map을 만들었습니다. 이 부분에서 행과 열의 인덱스를 계산할 때 헷갈리는 부분이 많았습니다. 이것을 해결하고 나서는, 없어지는 블록의 개수를 구하는 부분만 추가해서 반복문을 빠져나오면 풀 수 있는 문제였습니다.

< 문제 풀이 >

1. 주어진 String[] board 배열을 나누어서 char[m][n] 배열에 먼저 넣습니다.

2. 그리고 check 함수를 만들어서 2차원 char 배열을 돌면서 지울 수 있는 4블록을 visited 배열에 true라고 표시 합니다.

3. 여기에서 어떻게 true 라고 있는 visited 배열에 위에서 부터 채울까 생각을 해봤는데, 저는 ArrayList를 열 별로 만들어서 0번째부터 n번째 까지 모든 열을 돌면서 아래서 부터 차례대로 visited 가 false 인 부분을 ArrayList에 넣었습니다.

4. 그리고 나서 다시 map을 생성하는데, ArrayList에 담긴 문자들을 3번과 같이 반복문을 돌면서 map을 채웁니다.

5. 그러면 한번 시행 했을 때 4블록이 없어진 문자들이 map 배열에 갱신이 되게 됩니다.

6. 없어진 블록을 체크하는 것은 ArrayList에 배열을 채우면서 visited가 false 가 아닌 true 인 것을 더해주면 됩니다.

7. 이제 더이상 4블록을 지울게 없어서 while 문을 빠져나오는 방법은 flag 변수를 선언해서, check를 한 후에 visited가 true인 것이 하나도 없게 되면 flag 변수가 그대로 false 이기 때문에 break를 해줍니다.


import java.util.ArrayList;

class Solution {
    
    static char[][] map;
	static boolean[][] visited;
	static int a, b;
	static ArrayList<Character>[] line;
  public int solution(int m, int n, String[] board) {
      		int answer = 0;
		a = m;
		b = n;
		map = new char[a][b];

		for (int i = 0; i < board.length; i++) {
			char[] ch = board[i].toCharArray();
			for (int j = 0; j < b; j++) {
				map[i][j] = ch[j];
			}
		}
		
		while(true) {
		
			visited = new boolean[a][b];
			line = new ArrayList[b];
			boolean flag = false;

			for (int i = 0; i < b; i++) {
				line[i] = new ArrayList<Character>();
			}

			// 지워지는 4블록들 표시하기.
			for (int i = 0; i < a - 1; i++) {
				for (int j = 0; j < b - 1; j++) {
					if (map[i][j] == 0)
						continue;
					check(i, j);
				}
			}

			Outter: for (int i = 0; i < a; i++) {
				for (int j = 0; j < b; j++) {
					if (visited[i][j] == true) {
						flag = true;
						break Outter;
					}
				}
			}

			if (!flag) {
				break;
			}

			// 지워지는 4블록들 지우고, 지워진거 빼고 밑에서 부터 위에까지 행 단위로 line에 저장.
			for (int i = 0; i < b; i++) {
				for (int j = a - 1; j >= 0; j--) {
					if (visited[j][i] == false) {
						line[i].add(map[j][i]);
					} else {
						answer++;
					}
				}
			}

			map = new char[a][b];

			// 지워진 배열빼고 다시 char 배열에 저장.
			for (int i = 0; i < b; i++) {
				for (int j = a - 1; j >= 0; j--) {
					if (line[i].size() <= a - 1 - j)
						break;
					map[j][i] = line[i].get((a - 1) - j);
				}
			}
		}
		
		

		return answer;
  }
    public static void check(int x, int y) {
		if (isInside(x, y)) {
			if (map[x][y] == map[x + 1][y] && map[x][y] == map[x][y + 1] && map[x][y] == map[x + 1][y + 1]) {
				visited[x][y] = true;
				visited[x + 1][y] = true;
				visited[x][y + 1] = true;
				visited[x + 1][y + 1] = true;
			}
		}
	}

	public static boolean isInside(int x, int y) {
		if (x >= 0 && y >= 0 && x < a && y < b)
			return true;
		else
			return false;
	}
}
반응형

'알고리즘 > 카카오' 카테고리의 다른 글

[프로그래머스] 문자열 압축  (0) 2020.04.10
[프로그래머스] 후보키  (0) 2020.03.26
방금그곡  (0) 2019.09.08
뉴스 클러스터링  (0) 2019.09.05
캐시  (0) 2019.09.05