코드카타 풀이 및 랭킹 시스템 수정

김민재·2024년 9월 24일
0
post-custom-banner

숫자 변환하기

자연수 x를 y로 변환하려고 합니다. 사용할 수 있는 연산은 다음과 같습니다.
x에 n을 더합니다
x에 2를 곱합니다.
x에 3을 곱합니다.
자연수 x, y, n이 매개변수로 주어질 때, x를 y로 변환하기 위해 필요한 최소 연산 횟수를 return하도록 solution 함수를 완성해주세요. 이때 x를 y로 만들 수 없다면 -1을 return 해주세요.

이것을 처음봤을 때 드는 생각은 DFS나 BFS를 생각했다.
그렇지만 막상 어떻게 사용해야만 할까... 라는 생각이 들어서 여러모로 검색을 해보았다.

BFS

BFS는 넒이 우선 탐색이라고 해서 현재 노드의 근처에 있는 모든 노드들을 가고 나서 다음 노드로 넘어가는 방식이라고 한다.

BFS가 DFS와 다른 점은 위의 그림에서 보면 알겠지만 DFS는 하나의 방향으로 끝까지 나아간 후에 옆으로 나아가면서 탐색하는 것이고 BFS는 옆으로 나아가면서 하나하나씩 탐색하는 것이다.
즉,
끝까지가서 돌아오면서 탐색하는 것: DFS
하나하나씩 탐색하면서 끝까지 가는 것: BFS

이 BFS를 이제 문제에 적용시켜 보면
1. x의 값과 몇번 반복했는지를 정할 값(이때는 처음 시작이므로 0)을 먼저 Queue에 저장한다. 이때 이걸 확인했으므로 visit[x] = 1 을 남겨준다.
2. Queue에 있는 값([curr,count])을 뽑아내어 curr의 값이 y와 값이 같은지 비교한다.
2-1. 같으면 count를 반환하고
2-2. 아니라면 다음으로 넘어간다.
3. 여기서 우리는 BFS이기 떄문에 DFS와는 다르게 함수를 호출할 필요가 없이 근처에서 올 수 있는 값들을 찾아보아야만 한다.
1) x + n
2) x * 2
**3) x 3
이 3가지 경우에 해당하는 값들을 각각 Queue에 저장하고 해당하는 값을 방문했습니다.(visit[값] = 1) 라는 표시를 남겨주면 된다.

이걸 반복하는 것인데

function calc(curr, i , x , y , n) {
    switch(i) {
        case 0: 
            curr += n;
            break;
        case 1:
            curr *= 2;
            break;
        case 2:
            curr *= 3;
            break;
    }
    
    return curr;
}

function solution(x, y, n) {
    let answer = 0;
    
    function bfs() {
        let queue = [[x,0]];
        let visit = {};
        visit[x] = 1;
        
        while(queue.length) {
           let [curr,count] = queue.shift();
            
           if(curr === y) return count;
            
           for(let i = 0 ; i < 3; i++) {
               let save = calc(curr,i,x,y,n);
               if(save <= y && !visit[save]) {
                   visit[save] = 1;
                   queue.push([save, count + 1]);
               }
           } 
        }
        
        return -1;
    }
    
    
    
    return bfs();
}

이 코드를 직접 실행해보면 실행시간이 상당히 오래걸린다.
그 이유에 대해서 찾아보니 최소 값인 x에서부터 최대값인 y를 찾는다고 칠 때 x가 최소인 1 y가 최대인 1000000이라고 친다면 실행되는 경우의 수가 정말 많다.
그렇기에 이를 앞에서 찾는 것이 아닌 y 값에서부터 x를 찾는 것이다. 큰값에서부터 작은 값으로 찾기에 -,/로 비교를 하는데 여기서 2나 3으로 나누어 떨어지지 않는 값들을 배제해버리면 계산이 더 빠르다는 것이었다.

function calc(curr, i , x , y , n) {
    switch(i) {
        case 0: 
            curr -= n;
            break;
        case 1:
            if(curr % 2 === 0) {
                curr /= 2;
            }
            else {
                curr = 0;
            }         
            break;
        case 2:
            if(curr % 3 === 0) {
                curr /= 3;
            }
            else {
                curr = 0;
            }          
            break;
    }
    
    return curr;
}

function solution(x, y, n) {
    let answer = 0;
    
    function bfs() {
        let queue = [[y,0]];
        let visit = {};
        visit[y] = 1;
        
        while(queue.length) {
           let [curr,count] = queue.shift();
            
           if(curr === x) return count;
            
           for(let i = 0 ; i < 3; i++) {
               let save = calc(curr,i,x,y,n);
               if(save >= x && !visit[save]) {
                   visit[save] = 1;
                   queue.push([save, count + 1]);
               }
           }
        }
        
        return -1;
    }
    
    
    
    return bfs();
}

실제로 이렇게 해보니까 계산시간이 정말 빠르게 나왔고 이런 식의 처리 방법이 있다는 것을 세삼스레 다시 깨닫게 된다.

랭킹 시스템 수정

랭킹 테이블에서 전적을 표시하는 playRecords에 대해서 궁금증이 생겼다.
'과연 이것을 2개 이상일 떄 2개만 보여줄 수는 없을까?'

하면서 생각한 것이 이 방법인데, 많은 변화가 있었지만 matches 라는 것에서 누구와 대결하여 어떻게 이겼는지에 대해서 들어가 있는 배열 정보인데 이중 2가지만 slice로 가져와서 해당 레코드에 갱신하는 것이다.
이를 통해서 전체 레코드에서 2개의 playRecords만 가질 수 있게끔 할 수 있다.

그리고 이렇게 가져온 랭킹 시스템에서 순위를 매기기 위해서 map() 함수를 이용하여 index값으로 하나씩 랭킹을 매핑하는 식으로 작업을 했다.

profile
ㅇㅇ
post-custom-banner

0개의 댓글