개발조각

[프로그래머스] 모음 사전 본문

알고리즘🅰/프로그래머스

[프로그래머스] 모음 사전

개발조각 2022. 4. 20. 12:20
728x90
반응형

점점 프로그래머스 힘드네요.😂

문제풀이가 있으면 풀겠는데...

문제를 이해하고 규칙을 정하는 과정까지가 너무 힘들고 어떻게 해야 될지 점점 모르겠습니다.

어렸을 때 수학문제를 풀 때 공식과 개념을 파악하는 것처럼 알고리즘 문제에서도 그런 과정이 필요한가 봐요...

 

솔직히 문제에 대한 예시도 별로 안 나와있고 이것만 봐서 어떻게 풀라는 거야!!!!!!

질문하기가 없었으면 이걸 풀 수 있긴 했을까 의문이에요...😔


해결방안에 대해 설명하자면

사전에 알파벳 모음 'A', 'E', 'I', 'O', 'U'만을 사용하여 만들 수 있는, 길이 5 이하의 모든 단어가 수록되어 있습니다. 사전에서 첫 번째 단어는 "A"이고, 그다음은 "AA"이며, 마지막 단어는 "UUUUU"입니다.

이 정보를 총 합쳤을 때 경우의 수의 총합은 3905입니다.

 

경우의 수의 총합 = 5의 1제곱(5) + 5의 2제곱(25) + 5의 3제곱(125) + 5의 4제곱(625) + 5의 5제곱(3125) = 3905

 

경우의 수의 총합을 가지고 문자열 각 자리마다 얼마씩 더해주면 되는지 확인하면 됩니다.

예를 들어 word의 문자열 길이가 5라고 하면

 

word문자열의 n번째 자리

  • 0번째 : 3905 / 5 = 781
  • 1번째 : 3905 / 25 = 156.2 -> 156
  • 2번째 : 3905 / 125 = 31.24 -> 31
  • 3번째 : 3905 / 5 = 6.248 -> 6
  • 4번째 : 3905 / 3125 = 1.2496 -> 1

*여기서 소수점은 다 버림 했습니다.

 

위에 써둔 word문자열의 n번째가 어디인지

word문자열의 n번째가 [ 'A', 'E', 'I', 'O', 'U' ] 이 5개의 알파벳 중에 무엇인지 확인해주면 됩니다.

  • word문자열의 n번째 자리 * [ 'A', 'E', 'I', 'O', 'U' ]에서 해당하는 알파벳 위치 +1

이건 말로 설명하기 애매해서 예시로 설명하겠습니다.

 

예시)

word = "AAAAE"

  • 0번째(A) : word문자열의 0번째 자리 * ([ 'A', 'E', 'I', 'O', 'U' ]에서 해당하는 알파벳 위치) + 1 -> 781*0+1 -> 1
  • 1번째(A) : word문자열의 1번째 자리 * ([ 'A', 'E', 'I', 'O', 'U' ]에서 해당하는 알파벳 위치) + 1 -> 156*0+1 -> 1
  • 2번째(A) : word문자열의 2번째 자리 * ([ 'A', 'E', 'I', 'O', 'U' ]에서 해당하는 알파벳 위치) + 1 -> 31*0+1 -> 1
  • 3번째(A) : word문자열의 3번째 자리 * ([ 'A', 'E', 'I', 'O', 'U' ]에서 해당하는 알파벳 위치) + 1 -> 6*0+1 -> 1
  • 4번째(E) : word문자열의 4번째 자리 * ([ 'A', 'E', 'I', 'O', 'U' ]에서 해당하는 알파벳 위치) + 1 -> 1*1+1 -> 2

1+1+1+1+2 = 6

 

 

word = "AAAE"

  • 0번째(A) : word문자열의 0번째 자리 * ([ 'A', 'E', 'I', 'O', 'U' ]에서 해당하는 알파벳 위치) + 1 -> 781*0+1 -> 1
  • 1번째(A) : word문자열의 1번째 자리 * ([ 'A', 'E', 'I', 'O', 'U' ]에서 해당하는 알파벳 위치) + 1 -> 156*0+1 -> 1
  • 2번째(A) : word문자열의 2번째 자리 * ([ 'A', 'E', 'I', 'O', 'U' ]에서 해당하는 알파벳 위치) + 1 -> 31*0+1 -> 1
  • 3번째(E) : word문자열의 3번째 자리 * ([ 'A', 'E', 'I', 'O', 'U' ]에서 해당하는 알파벳 위치) + 1 -> 6*1+1 -> 7

1+1+1+7 = 10

 

 

word = "I"

  • 0번째(I) : word문자열의 0번째 자리 * ([ 'A', 'E', 'I', 'O', 'U' ]에서 해당하는 알파벳 위치) + 1 -> 781*2+1 -> 1565

1563

 

 

word = "EIO"

  • 0번째(E) : word문자열의 0번째 자리 * ([ 'A', 'E', 'I', 'O', 'U' ]에서 해당하는 알파벳 위치) + 1 -> 781*1+1 -> 782
  • 1번째(I) : word문자열의 1번째 자리 * ([ 'A', 'E', 'I', 'O', 'U' ]에서 해당하는 알파벳 위치) + 1 -> 156*2+1 -> 313
  • 2번째(O) : word문자열의 2번째 자리 * ([ 'A', 'E', 'I', 'O', 'U' ]에서 해당하는 알파벳 위치) + 1 -> 31*3+1 -> 94
E I O
0번째 : 781 1번째 : 156 2번째 : 31
[ 'A', 'E', 'I', 'O', 'U' ]에서 1번째 : 1 [ 'A', 'E', 'I', 'O', 'U' ]에서 2번째 : 2 [ 'A', 'E', 'I', 'O', 'U' ]에서 3번째 : 3
781*1+1 156*2+1 31*3+1

782 + 313 + 94 = 1189

 

 

해결방안 설명을 토대로 코드를 짜면 됩니다.


해결방안

function solution(word) {    
    // 버전 1
    let totalWord = 0;
    for(let i=1; i<6; i++) totalWord += Math.pow(5, i);
    
    var answer = 0;
    for(let idx = 0; idx< word.length; idx++){
        let idxValue = Math.floor(totalWord / Math.pow(5, idx+1))
        if(word[idx] === 'A') answer+= 1;
        else if(word[idx] === 'E') answer += idxValue +1;
        else if(word[idx] === 'I') answer += idxValue*2 +1;
        else if(word[idx] === 'O') answer += idxValue*3 +1;
        else if(word[idx] === 'U') answer += idxValue*4 +1;
    }
    return answer;
    
    // 버전 2
    return [...word].reduce((acc, cur, idx) => acc + [781, 156, 31, 6, 1][idx] * ['A', 'E', 'I', 'O', 'U'].indexOf(cur) + 1, 0);

}

이번에도 2가지 버전으로 들고 왔습니다.

버전 1은 위에 설명을 정직하게 다 쓴 방법이고요.

버전 2는 위에 설명에서 생략 할 수 있는 것을 생각하고 쓴 방법입니다.


버전 1

// 버전 1
let totalWord = 0;
for(let i=1; i<6; i++) totalWord += Math.pow(5, i);

var answer = 0;
for(let idx = 0; idx< word.length; idx++){
    let idxValue = Math.floor(totalWord / Math.pow(5, idx+1))
    if(word[idx] === 'A') answer+= 1;
    else if(word[idx] === 'E') answer += idxValue +1;
    else if(word[idx] === 'I') answer += idxValue*2 +1;
    else if(word[idx] === 'O') answer += idxValue*3 +1;
    else if(word[idx] === 'U') answer += idxValue*4 +1;
}
return answer;

해결방안 순서

  1. 경우의 수의 총합을 구해서 totalWord에 담아준다.
  2. word문자열의 길이만큼 for문으로 돌려준다.
  3. word문자열이 몇 번째인지, 해당 알파벳이 알파벳 중에서 몇 번째 에인지 따라 값 구해주기

 

1단계. 경우의 수의 총합을 구해서 totalWord에 담아준다.

let totalWord = 0;
for(let i=1; i<6; i++) totalWord += Math.pow(5, i);
  • Math.pow()함수는base^exponent처럼 base 에 exponent를 제곱한 값을 반환합니다.
  • Math.pow(base, exponent)
    • base : 밑 값.
    • exponent : 밑 을 제곱하기 위해 사용하는 지수.

 

경우의 수의 총합 = 5의 1제곱(5) + 5의 2제곱(25) + 5의 3제곱(125) + 5의 4제곱(625) + 5의 5제곱(3125) = 3905

totalWord = 3905

 

 

2단계. word문자열의 길이만큼 for문으로 돌려준다.

for(let idx = 0; idx< word.length; idx++)

 

 

3단계. word문자열이 몇 번째인지, 해당 알파벳이 알파벳 중에서 몇 번째 에인지 따라 값 구해주기

let idxValue = Math.floor(totalWord / Math.pow(5, idx+1))
if(word[idx] === 'A') answer+= 1;
else if(word[idx] === 'E') answer += idxValue +1;
else if(word[idx] === 'I') answer += idxValue*2 +1;
else if(word[idx] === 'O') answer += idxValue*3 +1;
else if(word[idx] === 'U') answer += idxValue*4 +1;
  • Math.floor() 함수는 주어진 숫자와 같거나 작은 정수 중에서 가장 큰 수를 반환합니다.
  • Math.pow()함수는base^exponent처럼 base 에 exponent를 제곱한 값을 반환합니다.

idxValue = 경우의 수의 총합 / 5의 i+1의 제곱 -> word문자열의 n번째 자리

  • A는 0을 곱하기 때문에 1이 나올 수밖에 없어서 +1이라고 썼습니다.

버전 2

return [...word].reduce((acc, cur, idx) => acc + [781, 156, 31, 6, 1][idx] * ['A', 'E', 'I', 'O', 'U'].indexOf(cur) + 1, 0);

해결방안 순서

  1. word문자열을 배열로 만들어준다.
  2. reduce를 사용한다.
    1. 배열에 미리 word문자열의 n번째 자리값을 담아주고 idx(현재 인덱스)를 사용하여 word문자열의 n번째 자리를 구한다.
    2. indexOf와 cur(현재 값)을 사용하여 해당 알파벳이 알파벳 중에서 몇 번째에 있는지 구한다.
    3. acc(누산기) + 앞에서 구한 word문자열의 n번째 자리* 해당 알파벳이 알파벳중에서 몇번째 + 1을 구해서 답을 리턴한다.

 

1단계. word문자열을 배열로 만들어준다.

[...word]

스프레드 연산자를 사용하면 문자열을 쉽게 배열로 만들 수 있습니다.

 

 

2단계. reduce를 사용한다.

// 버전 2
reduce((acc, cur, idx) => acc + [781, 156, 31, 6, 1][idx] * ['A', 'E', 'I', 'O', 'U'].indexOf(cur) + 1, 0);

1. 배열에 미리 word문자열의 n번째 자리값을 담아주고 idx(현재 인덱스)를 사용하여 word문자열의 n번째 자리를 구한다.

[781, 156, 31, 6, 1][idx]

여기서 [781, 156, 31, 6, 1]을 보시면 무슨 수를 넣었는지 알 수 있을 겁니다.

word문자열의 n번째 자리

  • 0번째 : 3905 / 5 = 781
  • 1번째 : 3905 / 25 = 156.2 -> 156
  • 2번째 : 3905 / 125 = 31.24 -> 31
  • 3번째 : 3905 / 5 = 6.248 -> 6
  • 4번째 : 3905 / 3125 = 1.2496 -> 1

이 값을 배열로 담아 주었습니다.

 

idx는 현재 인덱스를 나타낸 값임으로 

[781, 156, 31, 6, 1][idx]으로 쓰면 idx가 word배열의 idx가 몇 번째에 따라 word문자열의 n번째 자리를 구하게 됩니다.

 

 

2. indexOf와 cur(현재 값)을 사용하여 해당 알파벳이 알파벳 중에서 몇 번째에 있는지 구한다.

['A', 'E', 'I', 'O', 'U'].indexOf(cur)

여기서도 미리 알파벳 순서를 배열로 집어넣고

indexOf()를 사용하여 해당 알파벳이 배열에 몇번째에 위치했는지 구했습니다.

  • indexOf() 메서드는 배열에서 지정된 요소를 찾을 수 있는 첫 번째 인덱스를 반환하고 존재하지 않으면 -1을 반환합니다.

여기서 cur(현재 값) 임으로 [ 'A', 'E', 'I', 'O', 'U' ]중 하나일 테고

indexOf(cur)를 하면 각 해당하는 알파벳의 위치를 찾아주게 됩니다.

 

 

여기서 참고할 점은

reduce를 쓸 때는 acc+cur일 경우에는 초기값을 안 써도 괜찮지만 변형을 하여 쓰거나 idx까지 쓰면 초기값을 설정해주어야 됩니다.


프로그래머스 모음 사전 해결방안 설명은 여기까지입니다.

 

 

728x90
반응형
Comments