문제 소개
다음과 같은 숫자 이름 문자열이 있다고 가정해 보겠습니다.
const str = 'TOWNE';
이 문자열의 글자들을 재배열해 보면 두 개의 숫자 이름이 숨어 있는 것을 발견할 수 있습니다. 바로 2(TWO)와 1(ONE)입니다.
따라서 기대하는 출력값은 21입니다.
즉, 우리는 이렇게 글자가 뒤섞인 문자열을 입력받아 그 안에 포함된 숫자들을 찾아 반환하는 JavaScript 함수를 작성해야 합니다.
풀이 접근 방식
핵심 아이디어는 다음과 같습니다.
- 각 숫자 이름(ONE, TWO, THREE 등)에 대해 가능한 모든 순열(permutation)을 생성합니다.
- 생성된 순열 중 원본 문자열에 포함된 글자들로만 이루어진 것을 찾아 매칭합니다.
- 매칭된 숫자 이름의 위치 정보를 기록하고, 위치 순서대로 정렬하여 최종 숫자를 조합합니다.
구현 코드
다음은 위 접근 방식을 구현한 전체 코드입니다.
const str = 'TOWNE';
const findNumber = (str = '') => {
function stringPermutations(str) {
const res = [];
if (str.length == 1) return [str];
if (str.length == 2) return [str, str[1]+str[0]];
str.split('').forEach((chr, ind, arr) => {
let sub = [].concat(arr);
sub.splice(ind, 1);
stringPermutations(sub.join('')).forEach(function (perm) {
res.push(chr+perm);
});
});
return res;
}
const legend = {
'ONE': 1, 'TWO': 2, 'THREE': 3, 'FOUR': 4,
'FIVE': 5, 'SIX': 6, 'SEVEN': 7, 'EIGHT': 8,
'NINE': 9, 'ZERO': 0
};
const keys = Object.keys(legend);
const res = {};
const resArr = [];
let result = '';
keys.forEach(key => {
const match = stringPermutations(key).find(el => el.split('').every(char => str.includes(char)));
if(match){
const index = str.indexOf(match[0]);
if(!res.hasOwnProperty(key)){
res[key] = [index];
}else if(!res[key].includes(index)){
res[key].push(index);
};
};
});
Object.keys(res).forEach(word => {
resArr.push([word, ...res[word]]);
});
resArr.sort((a, b) => a[1] - b[1]);
resArr.forEach(sub => {
result = result + String(legend[sub[0]]).repeat(sub.length - 1);
});
return +result;
};
console.log(findNumber(str));코드 동작 설명
- stringPermutations 함수: 재귀적으로 각 숫자 이름의 모든 글자 순열을 생성합니다.
- legend 객체: 영문 숫자 이름과 해당 숫자를 매핑합니다.
- 매칭 단계: 각 숫자 이름의 순열 중 원본 문자열의 글자들로 구성 가능한 것을 찾고, 첫 글자의 인덱스를 기록합니다.
- 정렬 및 조합: 발견된 숫자들을 인덱스 순서대로 정렬한 뒤, 반복 횟수만큼 숫자를 이어 붙여 최종 결과를 만듭니다.
출력 결과
위 코드를 실행하면 콘솔에 다음과 같은 결과가 출력됩니다.
21
'TOWNE' 문자열에서 TWO(2)와 ONE(1)이 성공적으로 추출되어 21이라는 결과가 반환되었습니다.