JS-algorithm/프로그래머스

[프로그래머스] 체육복 (javascript)

yunieyunie 2022. 5. 4. 22:53

https://programmers.co.kr/learn/courses/30/lessons/42862

 

코딩테스트 연습 - 체육복

점심시간에 도둑이 들어, 일부 학생이 체육복을 도난당했습니다. 다행히 여벌 체육복이 있는 학생이 이들에게 체육복을 빌려주려 합니다. 학생들의 번호는 체격 순으로 매겨져 있어, 바로 앞번

programmers.co.kr

해결 방법

1. lost와 reserve에 같은 숫자가 없는 숫자만 뽑아 새로운 배열 만들기

2. reserve에 앞번호가 존재한다면, reserve에서 해당 번호 제거

3. reserve에 뒷번호가 존재한다면, reserve에서 해당 번호 제거

4. 2번과 3번에 모두 속하지 않으면 체육복을 빌릴 수 없는 학생이므로 전체 명수인 answer에서 1차감

 

 

풀이

function solution(n, lost, reserve) {
    var answer = n;

    // 체육복을 도난당했지만 여벌이 없어 진짜 빌려야 하는 학생들
    let real_lost = lost.filter(x => reserve.includes(x)==false);
    let real_reserve = reserve.filter(x => lost.includes(x)==false);
    real_lost.sort((a,b)=>a-b);
   
    for (let lost_number of real_lost){        
        // 앞번호의 학생에게 체육복을 빌릴 수 있는 학생
        if (real_reserve.includes(lost_number-1)){
            real_reserve.splice(real_reserve.indexOf(lost_number-1),1);
        // 뒷번호의 학생에게 체육복을 빌릴 수 있는 학생 
        } else if (real_reserve.includes(lost_number+1)){
            real_reserve.splice(real_reserve.indexOf(lost_number+1),1);
        // 앞,뒷번호의 학생 모두에게 체육복을 빌릴 수 없는 학생    
        } else {
            answer -= 1;
        }
    }
    return answer;
}

 

배운 점

 

1. for문으로 배열의 모든 요소를 대입해야할 땐 기존 배열을 변경하는 splice를 쓰지 말자

function solution(n, lost, reserve) {
    var answer = n;
    
    // 체육복을 도난당했지만 여벌이 없어 진짜 빌려야 하는 학생들
    for (let lost_num of lost){
        if (reserve.includes(lost_num)){
            reserve.splice(reserve.indexOf(lost_num),1);
            lost.splice(lost.indexOf(lost_num),1);
        }
    }

    for (let lost_number of lost){        
    	//앞번호 학생에게 빌릴 수 있는 학생
        if (reserve.includes(lost_number-1)){
            reserve.splice(reserve.indexOf(lost_number-1),1);
          //뒷번호 학생에게 빌릴 수 있는 학생  
        } else if (reserve.includes(lost_number+1)){
            reserve.splice(reserve.indexOf(lost_number+1),1);
          //앞뒤 학생 모두에게 빌릴 수 없는 학생  
        } else {
            answer -= 1;
        }
    }
    return answer;
}

처음에 짰던 위의 코드는 테스트 케이스 7, 13, 14번에서 실패가 떴다..

원인을 찾기 위해 다양한 예를 대입하고 console.log로 단계별 확인을 해본 결과, 

n=3, lost=[1, 2, 3, 4], reserve=[2, 3, 4]일 때 오류를 찾을 수 있었다

 

처음 for문에서 lost_num에 1이 입력되면 if문을 만족하지 않아 두번째로 2가 입력된다

2가 입력되면 if문을 만족하기 때문에 reserve와 lost에서 제외되는데,

이 때 나는 2가 lost에서 제외되어 lost=[1, 3, 4]가 되고, 세번째인 3이 lost_num에 대입되어 for문을 돈다고 생각했다

하지만 3을 건너뛰고 4가 입력되는 것을 확인했다

그 이유는 splice가 기존 배열을 변경함에 따라 i가 2일 때 a=[1, 3, 4]가 되고 세번째는 4가 되기 때문이다

 

따라서 기존 배열을 변경하는 splice를 사용하지 않고

다음과 같이 filter를 사용해 새로운 배열을 만들었다

 

function solution(n, lost, reserve) {
    var answer = n;
    let index = 0;
    
    // 체육복을 도난당했지만 여벌이 없어 진짜 빌려야 하는 학생들
    let real_lost = lost.filter(x => reserve.includes(x)==false);
    let real_reserve = reserve.filter(x => lost.includes(x)==false);
   
    for (let lost_number of real_lost){        
        // 앞번호의 학생에게 체육복을 빌릴 수 있는 학생
        if (real_reserve.includes(lost_number-1)){
            index = real_reserve.indexOf(lost_number-1)
            real_reserve.splice(index,1);
        // 뒷번호의 학생에게 체육복을 빌릴 수 있는 학생 
        } else if (real_reserve.includes(lost_number+1)){
            index = real_reserve.indexOf(lost_number+1)
            real_reserve.splice(index,1);
        // 앞뒷번호의 학생 모두에게 체육복을 빌릴 수 없는 학생    
        } else {
            answer -= 1;
        }
    }
    return answer;
}

이번에는 테스트 케이스 7번은 통과했지만 13, 14번은 여전히 실패였다

구글링 결과, real_lost가 정렬이 안돼있는 경우를 고려안했기 때문임을 알 수 있었다

예를 들면, n=5, lost=[4, 2], reserve=[3, 5]인 경우, 차례로 대입하면 4에겐 3이 빌려주기 때문에

2는 체육복을 빌릴 수 없다

하지만 오름차순으로 정렬을 해준다면 2는 3에게 빌리고 4는 5에게 빌려 모든 학생이 체육복을 갖게 된다

따라서 real_lost.sort((a,b)=>a-b);를 한 줄 추가해 lost를 오름차순 정렬을 해준다면 모든 테스트 케이스가 통과다

 

문제를 처음 읽었을 때는 금방 풀겠다 생각했는데 생각치 못한 부분에서 오류가 발생하고

또 생각지 못한 케이스가 있었다

꼼꼼히 따져보고 생각해보는 습관을 길러야겠다