# \[99클럽 코테 스터디 24일차 TIL]  프로그래머스 - 대충 만든 자판

## \[level 1] 대충 만든 자판 - 160586

[문제 링크](https://school.programmers.co.kr/learn/courses/30/lessons/160586#)

#### 문제 설명

휴대폰의 자판은 컴퓨터 키보드 자판과는 다르게 하나의 키에 여러 개의 문자가 할당될 수 있습니다. 키 하나에 여러 문자가 할당된 경우, 동일한 키를 연속해서 빠르게 누르면 할당된 순서대로 문자가 바뀝니다.

예를 들어, 1번 키에 "A", "B", "C" 순서대로 문자가 할당되어 있다면 1번 키를 한 번 누르면 "A", 두 번 누르면 "B", 세 번 누르면 "C"가 되는 식입니다.

같은 규칙을 적용해 아무렇게나 만든 휴대폰 자판이 있습니다. 이 휴대폰 자판은 키의 개수가 1개부터 최대 100개까지 있을 수 있으며, 특정 키를 눌렀을 때 입력되는 문자들도 무작위로 배열되어 있습니다. 또, 같은 문자가 자판 전체에 여러 번 할당된 경우도 있고, 키 하나에 같은 문자가 여러 번 할당된 경우도 있습니다. 심지어 아예 할당되지 않은 경우도 있습니다. 따라서 몇몇 문자열은 작성할 수 없을 수도 있습니다.

이 휴대폰 자판을 이용해 특정 문자열을 작성할 때, 키를 최소 몇 번 눌러야 그 문자열을 작성할 수 있는지 알아보고자 합니다.

1번 키부터 차례대로 할당된 문자들이 순서대로 담긴 문자열배열 `keymap`과 입력하려는 문자열들이 담긴 문자열 배열 `targets`가 주어질 때, 각 문자열을 작성하기 위해 키를 최소 몇 번씩 눌러야 하는지 순서대로 배열에 담아 return 하는 solution 함수를 완성해 주세요.

단, 목표 문자열을 작성할 수 없을 때는 -1을 저장합니다.

***

**제한사항**

* 1 ≤ `keymap`의 길이 ≤ 100
  * 1 ≤ `keymap`의 원소의 길이 ≤ 100
  * `keymap[i]`는 i + 1번 키를 눌렀을 때 순서대로 바뀌는 문자를 의미합니다.
    * 예를 들어 `keymap[0]` = "ABACD" 인 경우 1번 키를 한 번 누르면 A, 두 번 누르면 B, 세 번 누르면 A 가 됩니다.
  * `keymap`의 원소의 길이는 서로 다를 수 있습니다.
  * `keymap`의 원소는 알파벳 대문자로만 이루어져 있습니다.
* 1 ≤ `targets`의 길이 ≤ 100
  * 1 ≤ `targets`의 원소의 길이 ≤ 100
  * `targets`의 원소는 알파벳 대문자로만 이루어져 있습니다.

***

**입출력 예**

| keymap              | targets          | result  |
| ------------------- | ---------------- | ------- |
| \["ABACD", "BCEFD"] | \["ABCD","AABB"] | \[9, 4] |
| \["AA"]             | \["B"]           | \[-1]   |
| \["AGZ", "BSSS"]    | \["ASA","BGZ"]   | \[4, 6] |

***

**입출력 예 설명**

입출력 예 #1

* "ABCD"의 경우,
* 1번 키 한 번 → A
* 2번 키 한 번 → B
* 2번 키 두 번 → C
* 1번 키 다섯 번 → D
* 따라서 총합인 9를 첫 번째 인덱스에 저장합니다.
* "AABB"의 경우,
* 1번 키 한 번 → A
* 1번 키 한 번 → A
* 2번 키 한 번 → B
* 2번 키 한 번 → B
* 따라서 총합인 4를 두 번째 인덱스에 저장합니다.
* 결과적으로 \[9,4]를 return 합니다.

입출력 예 #2

* "B"의 경우, 'B'가 어디에도 존재하지 않기 때문에 -1을 첫 번째 인덱스에 저장합니다.
* 결과적으로 \[-1]을 return 합니다.

입출력 예 #3

* "ASA"의 경우,
* 1번 키 한 번 → A
* 2번 키 두 번 → S
* 1번 키 한 번 → A
* 따라서 총합인 4를 첫 번째 인덱스에 저장합니다.
* "BGZ"의 경우,
* 2번 키 한 번 → B
* 1번 키 두 번 → G
* 1번 키 세 번 → Z
* 따라서 총합인 6을 두 번째 인덱스에 저장합니다.
* 결과적으로 \[4, 6]을 return 합니다.

***

## 풀이 코드

```java
class Solution {
    public int[] solution(String[] keymap, String[] targets) {
        int[] answer = new int[targets.length];
        int[] keyCnt = new int[26]; // 알파벳별 최소 위치 입력할 배열
        for (String key : keymap) {
            char[] chars = key.toCharArray();
            for (int i = 0; i < chars.length; i++) {
                int n = chars[i] - 'A'; // 하나의 키에 할당된 문자
                if (keyCnt[n] == 0) keyCnt[n] = i + 1; // 처음 나온 문자인 경우
                else if (keyCnt[n] > i + 1) keyCnt[n] = i + 1; // 문자의 인덱스가 기존 것보다 작은 경우
            }
        }
        
        for (int i = 0; i < targets.length; i++) {
            int cnt = 0;
            for (char t : targets[i].toCharArray()) {
                int kc = keyCnt[t - 'A'];
                if (kc == 0) { // 작성할 문자가 자판에 없는 경우
                    cnt = -1;
                    break;
                }
                cnt += kc;
            }
            answer[i] = cnt;
        }
        return answer;
    }
}
```

* Time: 0.67 ms
* Memory: 80.2 MB

풀이 과정 자체는 정말 쉬웠는데 문제를 주의 깊게 보질 않아서 좀 헤맸다. 위 풀이에서 두번째 이중 `for`문의 `break`문이 있는 조건식이 처음엔 없었다. 그래서 만약 입력 값이 아래와 같이 주어지는 경우, 결과 값이 틀리게 된다.

* 자판(keymap) : \["ABC"]
* 작성할 문자열(targets) : \["DA"]
* 결과 값 : -1

문제 자체에서 `단, 목표 문자열을 작성할 수 없을 때는 -1을 저장합니다.` 라고 해줬는데도 불구하고 `break` 문 조건식이 없이 구현했다. 해당 조건식이 없으면 결과 값은 1 이 된다. 왜냐하면 작성할 문자열의 "A" 값은 자판에 있기 때문이다. 기초적인 부분에서 실수했다.

조건 처리가 중복되는 곳이 있어서 간단히 개선해봤다.

### 개선하기

```java
class Solution {
    public int[] solution(String[] keymap, String[] targets) {
        int[] answer = new int[targets.length];
        int[] keyCnt = new int[26]; // 알파벳별 최소 위치 입력할 배열
        for (String key : keymap) {
            char[] chars = key.toCharArray();
            for (int i = 0; i < chars.length; i++) {
                int n = chars[i] - 'A'; // 하나의 키에 할당된 문자
                // 처음 나온 문자이거나 문자의 인덱스가 기존 것보다 작은 경우
                if (keyCnt[n] == 0 || keyCnt[n] > i + 1) keyCnt[n] = i + 1;
            }
        }

        for (int i = 0; i < targets.length; i++) {
            int cnt = 0;
            for (char t : targets[i].toCharArray()) {
                int kc = keyCnt[t - 'A'];
                if (kc == 0) { // 작성할 문자가 자판에 없는 경우
                    cnt = -1;
                    break;
                }
                cnt += kc;
            }
            answer[i] = cnt;
        }
        return answer;
    }
}
```

* Time: 0.63 ms
* Memory: 74.8 MB

조건식 하나로 합쳤다고 0.04 ms 가 줄었다.

***

## 돌아보기

한번에 딱 맞출 수 있었는데 조금 더 신중해보자.

***

\#99클럽 #코딩테스트준비 #개발자취업 #항해99 #TIL


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://devlee.gitbook.io/docs/study/99/99-24-til.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
