LEVEL4_프로그래머스_가사 검색
Written on October 29, 2020
문제
친구들로부터 천재 프로그래머로 불리는 프로도는 음악을 하는 친구로부터 자신이 좋아하는 노래 가사에 사용된 단어들 중에 특정 키워드가 몇 개 포함되어 있는지 궁금하니 프로그램으로 개발해 달라는 제안을 받았습니다.
그 제안 사항 중, 키워드는 와일드카드 문자중 하나인 ‘?’가 포함된 패턴 형태의 문자열을 뜻합니다. 와일드카드 문자인 ‘?’는 글자 하나를 의미하며, 어떤 문자에도 매치된다고 가정합니다. 예를 들어 "fro??"
는 "frodo"
, "front"
, "frost"
등에 매치되지만 "frame"
, "frozen"
에는 매치되지 않습니다.
가사에 사용된 모든 단어들이 담긴 배열 words
와 찾고자 하는 키워드가 담긴 배열 queries
가 주어질 때, 각 키워드 별로 매치된 단어가 몇 개인지 순서대로 배열에 담아 반환하도록 solution
함수를 완성해 주세요.
가사 단어 제한사항
words
의 길이(가사 단어의 개수)는 2 이상 100,000 이하입니다.- 각 가사 단어의 길이는 1 이상 10,000 이하로 빈 문자열인 경우는 없습니다.
- 전체 가사 단어 길이의 합은 2 이상 1,000,000 이하입니다.
- 가사에 동일 단어가 여러 번 나올 경우 중복을 제거하고
words
에는 하나로만 제공됩니다. - 각 가사 단어는 오직 알파벳 소문자로만 구성되어 있으며, 특수문자나 숫자는 포함하지 않는 것으로 가정합니다.
검색 키워드 제한사항
queries
의 길이(검색 키워드 개수)는 2 이상 100,000 이하입니다.- 각 검색 키워드의 길이는 1 이상 10,000 이하로 빈 문자열인 경우는 없습니다.
- 전체 검색 키워드 길이의 합은 2 이상 1,000,000 이하입니다.
- 검색 키워드는 중복될 수도 있습니다.
- 각 검색 키워드는 오직 알파벳 소문자와 와일드카드 문자인
'?'
로만 구성되어 있으며, 특수문자나 숫자는 포함하지 않는 것으로 가정합니다. - 검색 키워드는 와일드카드 문자인
'?'
가 하나 이상 포함돼 있으며,'?'
는 각 검색 키워드의 접두사 아니면 접미사 중 하나로만 주어집니다.- 예를 들어
"??odo"
,"fro??"
,"?????"
는 가능한 키워드입니다. - 반면에
"frodo"
(‘?’가 없음),"fr?do"
('?'
가 중간에 있음),"?ro??"
('?'
가 양쪽에 있음)는 불가능한 키워드입니다.
- 예를 들어
입출력 예
words | queries | result |
---|---|---|
[“frodo”, “front”, “frost”, “frozen”, “frame”, “kakao”] | [“fro??”, “????o”, “fr???”, “fro???”, “pro?”] | [3, 2, 4, 1, 0] |
입출력 예에 대한 설명
"fro??"
는"frodo"
,"front"
,"frost"
에 매치되므로 3입니다."????o"
는"frodo"
,"kakao"
에 매치되므로 2입니다."fr???"
는"frodo"
,"front"
,"frost"
,"frame"
에 매치되므로 4입니다."fro???"
는"frozen"
에 매치되므로 1입니다."pro?"
는 매치되는 가사 단어가 없으므로 0 입니다.
풀이1
function isMatched(word, query){
let result = true;
for(let i = 0; i < query.length; i++){
if(query[i] !== '?'){
if(query[i] !== word[i]){
result = false;
break;
}
}
}
return result;
}
function solution(words, queries) {
let answer = Array.from({length: queries.length}, v => 0);
words.forEach(word => {
queries.forEach((query, index) => {
if(query.length === word.length){
if(isMatched(word, query)){
answer[index]++;
}
}
})
})
return answer;
}
풀이2
단어를 검색할 때 많이 사용하는 Trie(트라이)
자료구조를 활용하여 효율성을 개선한 코드
function trieGen(words){
let tries = {};
words.forEach(word => {
let currTrie = tries;
const len = word.length;
if(!currTrie[len]){
currTrie[len] = {};
}
currTrie = currTrie[len];
for(let i = 0; i < len; i++){
if(currTrie[word[i]]){
currTrie[word[i]][0] += 1;
} else {
currTrie[word[i]] = [1, {}];
}
currTrie = currTrie[word[i]][1];
}
});
return tries;
}
function reverseString(string){
return string.split('').reverse().join('');
};
function search(trie, query){
let answer = 0;
if(trie){
const queryArray = query.split('');
let currTrie = trie;
for(let i = 0; i < query.length; i++){
const q = query[i];
if(q === '?'){
const values = Object.values(currTrie);
answer = values.reduce((acc, curr) => {
return acc + curr[0];
}, 0);
break;
}
if(currTrie[q]){
currTrie = currTrie[q][1];
} else {
break;
}
}
};
return answer;
}
function solution(words, queries) {
let answer = [];
let tries = trieGen(words);
let reversedTries = trieGen(words.map(word => reverseString(word)));
queries.forEach(query => {
const len = query.length;
if(query.startsWith('?')){
const reversedQuery = reverseString(query);
answer.push(search(reversedTries[len], reversedQuery));
} else {
answer.push(search(tries[len], query));
}
});
return answer;
}
문제바로가기
👩🏻💻 배우는 것을 즐기는 프론트엔드 개발자 입니다
부족한 블로그에 방문해 주셔서 감사합니다 🙇🏻♀️
in the process of becoming the best version of myself