프로그래머스 L1 - 체육복

2024. 3. 25. 16:24알고리즘/프로그래머스

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

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

해석

학생이 5명이고 도난당한 사람이 [2, 4]이고 3번만 여분의 옷을 가지고 있다고 가정하자.

학생들의 체육복의 갯수를 카운팅해야하므로 체육복의 갯수를 저장할 배열을 만든다.

그리고 체육복이 0인 학생을 찾아서 양쪽 학생들 중 빌릴 수 있는 학생이 있다면 옷을 빌린다.

그렇다면 2개가 있던 학생은 1개가 되고, 0개가 있던 학생은 1개가 된다.

 

하지만 이 문제는 다양한 케이스를 고려해야한다.

일단 왼쪽에게 빌릴 수 있고 오른쪽에게 빌릴 수 없는 경우와 오른쪽에게 빌릴 수 있고 왼쪽에게 빌릴 수 없는 경우는 찾기 쉽다. 그런데 왼쪽에게도 빌릴 수 있고 오른쪽에게도 빌릴 수 있다면?

이 경우에는 아무에게나 빌리면 안된다. 조건을 따져봐야한다.

위의 예시에서 2번 학생이 3번 학생에게 빌리면 4번 학생은 옷을 빌리지 못한다.

하지만 1번 학생에게 빌리면 모두 옷을 빌릴 수 있다.

그렇기 때문에 양쪽 모두에게 빌릴 수 있는 경우라면 그 다음 학생이 옷을 빌려야되는 상황인지 파악해야한다.

즉, 위의 예시에서는 3번 학생의 다음 학생인 4번 학생이 옷을 빌려야되는 상황이라면 1번 학생에게 빌려야한다.

만일 왼쪽 학생의 이전 학생이 옷을 빌려야되는 상황이라면 반대로 오른쪽 학생에게 빌려야한다.

 

function solution(n, lost, reserve) {
    let ret = 0;
    let cnt = Array.from({length:n+2}).fill(1);
    cnt[0] = -1;
    cnt[cnt.length-1] = -1;
    reserve.forEach((n)=>cnt[n]+=1);
    lost.forEach((n)=>cnt[n]-=1);
    for(let i = 1; i<cnt.length; i++){
        if(cnt[i]===0){
            if(cnt[i-1]<=1 && cnt[i+1]>=2){
                cnt[i+1]-=1;
                cnt[i]+=1;
            }
            else if(cnt[i-1]>=2 && cnt[i+1]<=1){
                cnt[i-1]-=1;
                cnt[i]+=1;
            }
            else if(cnt[i-1]>=2 && cnt[i+1]>=2){
                if(cnt[i+2]===0){
                    cnt[i-1]-=1;
                    cnt[i]+=1;
                } else if(cnt[i-2]===0){
                    cnt[i+1]-=1;
                    cnt[i]+=1;
                } else{
                    cnt[i+1]-=1;
                    cnt[i]+=1;
                }
            }
        }
    }
    cnt.forEach((n)=>{
        if(n>=1) ret++
    });
    return ret;
}

조건문이 너무 많아서 오류가 생겼을 때 어떤 조건에 오류가 생겼는지 파악하기 힘들다.

더 좋은 코드를 찾아보았다.

 

function solution(n, lost, reserve) {
    const students = {};
    let answer = 0;
    for(let i = 1; i <= n; i++){
        students[i] = 1;
    }
    lost.forEach(number => students[number] -= 1);
    reserve.forEach(number => students[number] += 1);

    for(let i = 1; i <= n; i++){
        if(students[i] === 2 && students[i-1] === 0){
                students[i-1]++;
                students[i]--;
        } else if(students[i] === 2 && students[i+1] === 0){
                students[i+1]++;
                students[i]--;
        }
    }
    for(let key in students){
        if(students[key] >= 1){
            answer++;
        }
    }
    return answer;
}

이 코드는 학생들의 체육복 갯수를 객체에 저장했다.

그리고 객체의 요소를 순회하며 양옆에 빌려줄 사람이 있는지를 판단한다.

내 코드는 빌려야되는 사람들을 기준으로 구현했는데 이 코드는 여벌 옷이 있는 사람을 기준으로 구현했다.

사실 여벌 옷이 있다면 옷을 빌려주는 경우는 왼쪽이 없거나 오른쪽이 없는 두 가지 케이스밖에 없다.

그 외에는 옷을 빌려줄 필요가 없기 때문이다.

따라서 두 가지 경우만 확인해주면 된다. 이렇게 접근했을 때 엄청나게 많아지는 if문을 제거할 수 있다.