1. 문제

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

 

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

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

programmers.co.kr

문제 설명

블라인드 공채를 통과한 신입 사원 라이언은 신규 게임 개발 업무를 맡게 되었다. 이번에 출시할 게임 제목은프렌즈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

2. 어떻게 풀까?

  1. 입력으로 주어진 String 배열 board를 이차원 배열로 만든다.
  2. 이차원 배열의 현재 index의 block을 기준으로 block을 지울 수 있는지 확인한다.
  3. 지운 이후 위쪽의 block들을 아래로 내린다.
  4. 지울 수 있는 block이 없을 때까지 반복한다.
  5. 해결 과정은 명확하게 이해할 수 있는데, 이것을 코드로 작성하는데 계속 막히고, 틀렸다. 특히, 지울 수 있는지 확인하는 과정에서 boolean 타입을 선언해서 확인하려했는데, 잘 안됐다. 그래서 답을 참고했다.

velog.io/@hyeon930/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%ED%94%84%EB%A0%8C%EC%A6%884%EB%B8%94%EB%A1%9D-Java

 

[프로그래머스] 프렌즈4블록 (Java)

프로그래머스 프렌즈4블록이 문제의 핵심은 다음과 같다.4x4 블록이 같을 경우 지워지는데, 4x4가 겹쳐있는 경우에도 모두 지워진다.따라서, 이 문제는사라질 블록을 모두 체크한다.체크된 블록

velog.io


3. 코드

테스트 코드

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.*;

import org.junit.Test;

public class SolutionTest {

  @Test
  public void test1() {
    String[] board = {"CCBDE", "AAADE", "AAABF", "CCBBF"};
    assertThat(new Solution().solution(4, 5, board), is(14));
  }

  @Test
  public void test2() {
    String[] board = {"TTTANT", "RRFACC", "RRRFCC", "TRRRAA", "TTMMMF", "TMMTTJ"};
    assertThat(new Solution().solution(6, 6, board), is(15));
  }

}

실제 코드

public class Solution {

  public int solution(int m, int n, String[] board) {
    String[][] table = buildTable(m, n, board);
    int count = 0;

    while (true) {
      int dropBlockCount = countFourBlock(m, n, table);
      if (dropBlockCount == 0) {
        break;
      }
      count += dropBlockCount;
      dropTable(m, n, table);
    }

    return count;
  }

  private String[][] buildTable(int m, int n, String[] board) {
    String[][] table = new String[m][n];
    for (int i = 0; i < m; i++) {
      for (int j = 0; j < n; j++) {
        table[i][j] = board[i].charAt(j) + "";
      }
    }
    return table;
  }

  private int countFourBlock(int m, int n, String[][] table) {

    boolean[][] check = new boolean[m][n];

    for (int row = 0; row < m - 1; row++) {
      for (int col = 0; col < n - 1; col++) {
        if (table[row][col].equals(".")) {
          continue;
        }
        checkFourBlock(table, check, row, col);
      }
    }

    int count = 0;
    for (int row = 0; row < m; row++) {
      for (int col = 0; col < n; col++) {
        if (check[row][col]) {
          count++;
          table[row][col] = ".";
        }
      }
    }

    return count;
  }

  private void checkFourBlock(String[][] table, boolean[][] check, int currentRow,
      int currentCol) {
    String currentBlock = table[currentRow][currentCol];

    for (int row = currentRow; row < currentRow + 2; row++) {
      for (int col = currentCol; col < currentCol + 2; col++) {
        if (!table[row][col].equals(currentBlock)) {
          return;
        }
      }
    }

    for (int row = currentRow; row < currentRow + 2; row++) {
      for (int col = currentCol; col < currentCol + 2; col++) {
        check[row][col] = true;
      }
    }
  }

  private void dropTable(int m, int n, String[][] table) {
    for (int col = 0; col < n; col++) {
      for (int row = m - 1; row >= 0; row--) {
        if (table[row][col].equals(".")) {
          for (int notDotRow = row - 1; notDotRow >= 0; notDotRow--) {
            if (!table[notDotRow][col].equals(".")) {
              table[row][col] = table[notDotRow][col];
              table[notDotRow][col] = ".";
              break;
            }
          }
        }
      }
    }
  }

}
  • buildTable()에서 일차원 배열의 board를 이차원 배열로 만들었다.
  • 반복문을 돌며 countFourBlock()을 통해 지울 수 있는 block의 수를 계산 후, 전체 count에 더해주고 dropTable()을 통해 지웠다.
  • countFourBlock()에서 지울 수 있는 block인지 확인하는 boolean 이차원 배열을 선언 후, checkFourBlock()을 통해그림의 왼쪽 위부터 차례대로 확인했다. 마지막 행과 열은 확인 할 수 없기 때문에 반복문을 m-1, n-1까지만 돌며 확인했다. 지울 수 있는 block은 .으로 바꿔주었다.
  • dropTable()에서 element가 .인 칸을 찾은 후에 그 위로 .가 아닌 칸을 찾아서 두 element를 바꿔주었다.

4. 느낀 점

이차원 배열을 왼쪽 위부터 오른쪽 아래까지 차례대로 확인 👉 지울 수 있는 블록이라면 따로 마킹 👉 이차원 배열에서 마킹해놓은 개수를 덧셈 👉 블록들 삭제 👉 지울 수 있는 블록이 없을 때까지 반복

이라는 흐름은 머리로 간단히 그려졌는데, 막상 코드로 구현하려고 할 때 어려움을 느꼈다.

마킹을 어떻게 해야할까? Key, Value로 구현해야하나? 그럼 Entry를 써야하나? 이런 고민들도 있었고,

지울 수 있는 블록들은 어떻게 삭제를 해야할까? 배열에서는 delete하기 어려우니 List를 써야하나? 하는 고민도 있었다.

다른 분이 푼 코드를 보니, 그냥 따로 boolean 타입의 이차원 배열을 선언하여 해결했고

배열은 delete 대신 .으로 바꿔주었다.

어렵다 ㅜㅜ

1. 문제

https://www.codewars.com/kata/557f6437bf8dcdd135000010

 

Codewars: Achieve mastery through challenge

Codewars is where developers achieve code mastery through challenge. Train on kata in the dojo and reach your highest potential.

www.codewars.com

 

문제 설명

n mathematics, the factorial of integer n is written as n!. It is equal to the product of n and every integer preceding it. For example: 5! = 1 x 2 x 3 x 4 x 5 = 120

Your mission is simple: write a function that takes an integer n and returns the value of n!.

You are guaranteed an integer argument. For any values outside the non-negative range, return null, nil or None (return an empty string "" in C and C++). For non-negative numbers a full length number is expected for example, return 25! = "15511210043330985984000000" as a string.

For more on factorials, see http://en.wikipedia.org/wiki/Factorial

NOTES:

  • The use of BigInteger or BigNumber functions has been disabled, this requires a complex solution

  • I have removed the use of require in the javascript language.

입출력 예

1! 👉 "1"

5! 👉 "120"

9! 👉 "362880"

15! 👉 "1307674368000"

25! 👉 "15511210043330985984000000"

 


2. 어떻게 풀까?

 

간단하게 팩토리얼 구하는 함수를 구현해라는 문제인데, NOTE를 보면 BigInteger나 BigNumber를 쓰지 말라고 한다. 이러면 방법을 잘 모르겠다. 처음에는 bit별로 나누어서 list에 저장하고 bit끼리 더하면 되겠다 생각했는데 생각처럼 잘 되지 않았다. 그래서 결국 답을 봤다.

근데 답보니까 다 BigInteger를 썼는데 ㅋㅋ.. 그중에 안쓴 답이 있어서 며칠 동안 다시 풀면서 직접 코드를 짜 봤다.

 


3. 코드

 

답을 보고 내가 리팩터링 한 코드

 

테스트 코드

package doNotSolve.codewars.kyu4.largeFactorials_20201029;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.*;

import org.junit.Test;

public class KataTest {

  @Test
  public void test1() {
    assertThat(Kata.factorial(1), is("1"));
  }

  @Test
  public void test2() {
    assertThat(Kata.factorial(2), is("2"));
  }

  @Test
  public void test3() {
    assertThat(Kata.factorial(5), is("120"));
  }

  @Test
  public void test4() {
    assertThat(Kata.factorial(15), is("1307674368000"));
  }

  @Test
  public void test5() {
    assertThat(Kata.factorial(25), is("15511210043330985984000000"));
  }
}

 

실제 코드

package doNotSolve.codewars.kyu4.largeFactorials_20201029;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class KataAgain {

  static int carry;

  public static String factorials(int n) {
    List<Integer> digits = new ArrayList<>();
    int value = n;
    saveDigits(digits, value);

    for (value = n - 1; value > 1; value--) {
      List<Integer> targetDigits = new ArrayList<>();
      carry = 0;
      saveDigits(digits, targetDigits, value);

      saveDigits(targetDigits, carry);
      digits = targetDigits;
    }

    return getResultString(digits);
  }

  private static void saveDigits(List<Integer> digits, List<Integer> targetDigits, int value) {
    for (Integer digit : digits) {
      int product = value * digit + carry;
      targetDigits.add(product % 10);
      carry = product / 10;
    }
  }

  private static void saveDigits(List<Integer> digits, int value) {
    if (value == 0) {
      return;
    }
    while (value > 0) {
      digits.add(value % 10);
      value /= 10;
    }
  }

  private static String getResultString(List<Integer> digits) {
    String reversedDigits = digits.stream().map(String::valueOf).collect(Collectors.joining());
    return new StringBuilder(reversedDigits).reverse().toString();
  }
}

4. 느낀 점

memoization 방법으로 팩토리얼을 구현하면 타입을 long으로 해도 20! 에서 오버플로우가 발생한다. 따라서 큰 값의 팩토리얼을 구하려면 BigInteger을 사용해왔는데 새로운 방법을 알게 되었다. 팩토리얼 외에도 피보나치수열도 이 방법으로 할 수 있지 않을까? 생각이 들었다.

+ Recent posts