[프로그래머스 | Javascript] 대충 만든 자판

박기영·2023년 9월 18일
0

프로그래머스

목록 보기
123/159
post-custom-banner

solution

function solution(keymap, targets) {    
    let result = [];
    let trie = new Trie();
    
  	// keymap으로 Trie 생성
    for(key of keymap){
        trie.addWord(key);
    }
    
  	// targets에 적힌 각각의 문자열에 대해 결과를 판별
    for(let target of targets){
      	// 각 문자열을 구성할 때, 키보드가 눌린 횟수
        let pushCount = 0;
        
        for(let char of target){
            const level = trie.BFS(char);
            
            // level이 -1이라면 문자열을 구성할 수 없다는 뜻이므로
          	// result에 -1이 들어갈 수 있도록 처리한다.
            if(level === -1){
                pushCount = -1;
                break;
            }
            
            pushCount += level;
        }
        
        result.push(pushCount);
    }
    
    return result;
}

class Node{
    constructor(){
        this.children = {};
        this.isEndOfWord = false;
    }
}

class Trie{
    constructor(){
        this.root = new Node();
    }
    
    addWord(word){
        let current = this.root;
        
        for(let char of word){
            if(!current.children[char]){
                current.children[char] = new Node();
            }
            
            current = current.children[char];
        }
        
        current.isEndOfWord = true;
    }
    
    BFS(str){
        let queue = [];
		let node = this.root;
        let levelCount = 0;

		queue.push(node);

		while(queue.length > 0){
            const sameLevelLength = queue.length;
            let found = false;

            for(let i = 0; i < sameLevelLength; i++){
                node = queue.shift();
                
              	// node의 자식 중 str이 있으면, 그 자식 노드가 최소 level을 가진다.
                if(node.children[str]){
                    found = true;
                    break;
                }
            
                // 현재 node가 자식으로 가지고 있는 모든 노드를 queue에 넣는다.
                for(let child in node.children){
                    queue.push(node.children[child]);
                }
            }
            
            if(found){
                return ++levelCount;
            }
            
          	// 순회를 모두 마쳤음에도 일치하는 키를 찾지 못했으며
          	// 더이상 순회할 키가 없는 경우에는 문자열을 생성할 수 없다고 판단
            if(queue.length === 0){
                return -1;
            }

          	// 다음 level로 들어감을 의미
            levelCount++;
		}
        
        return -1;
    }
}

이 문제는 문자열을 다루는 문제이고, 키가 눌릴 때마다 다음 문자열이 나온다는 점에서 Trie 구조가 생각났다.
최소한의 횟수로 문자열을 완성하기 위해서는 몇 번 눌렀는지를 아는 것이 중요했고,
이는 Trie에서 level을 활용하는 것으로 구현할 수 있겠다고 판단했다.
따라서, Trie를 구성하는 것은 keymap을 사용하는 것으로 결정했다.

targets으로 주어진 문자열들을 만들기 위해 필요한 최소한의 키 입력 횟수를 구하는 것이기 때문에,
Trie에 대하여 BFS를 진행하면, 특정 문자열을 입력할 수 있는 최소한의 키 입력 횟수를 얻을 수 있다.
따라서, targets로 주어진 문자열들의 각 문자에 대해 한번씩 BFS를 진행한다.

Trie는 루트 노드가 값을 가지고 있는 것이 아니기 때문에, 바로 children을 탐색하는 것으로 진행해도 된다.
자식 노드 중에 키로 입력할 수 있는 것이 있다면, 그 때가 가장 낮은 level이므로,
level + 1(루트가 level 0라고 가정했기 때문)을 반환한다.
만약, 모든 노드를 순회했음에도 아무 결과를 얻지 못했다면 더 이상 진행할 수 없는 문자열이므로 -1을 반환한다.

profile
나를 믿는 사람들을, 실망시키지 않도록
post-custom-banner

1개의 댓글

comment-user-thumbnail
2023년 9월 18일

자판을 대충 만들지 마세요

답글 달기