본문 바로가기
프론트엔드로 가는 길/프로그래머스

58. 체육복

by woody-j 2023. 9. 14.

 

https://school.programmers.co.kr/learn/courses/30/lessons/42862?itm_content=course14743

[문제설명]

 

프로그래머스

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

programmers.co.kr

문제 설명
점심시간에 도둑이 들어, 일부 학생이 체육복을 도난당했습니다.
다행히 여벌 체육복이 있는 학생이 이들에게 체육복을 빌려주려 합니다.
학생들의 번호는 체격 순으로 매겨져 있어, 바로 앞번호의 학생이나 바로 뒷번호의 학생에게만 체육복을 빌려줄 수 있습니다.
예를 들어, 4번 학생은 3번 학생이나 5번 학생에게만 체육복을 빌려줄 수 있습니다.
체육복이 없으면 수업을 들을 수 없기 때문에 체육복을 적절히 빌려 최대한 많은 학생이 체육수업을 들어야 합니다.
전체 학생의 수 n,
체육복을 도난당한 학생들의 번호가 담긴 배열 lost,
여벌의 체육복을 가져온 학생들의 번호가 담긴 배열 reserve가 매개변수로 주어질 때,
체육수업을 들을 수 있는 학생의 최댓값을 return 하도록 solution 함수를 작성해주세요.

제한사항
전체 학생의 수는 2명 이상 30명 이하입니다.
체육복을 도난당한 학생의 수는 1명 이상 n명 이하이고 중복되는 번호는 없습니다.
여벌의 체육복을 가져온 학생의 수는 1명 이상 n명 이하이고 중복되는 번호는 없습니다.
여벌 체육복이 있는 학생만 다른 학생에게 체육복을 빌려줄 수 있습니다.
여벌 체육복을 가져온 학생이 체육복을 도난당했을 수 있습니다.
이때 이 학생은 체육복을 하나만 도난당했다고 가정하며, 남은 체육복이 하나이기에 다른 학생에게는 체육복을 빌려줄 수 없습니다.

[ 문제 풀이 ]

 

첫번째 풀이 -> 문제 생김

1. 번호 우선 배열

2. lost와 reserve가 동일한 원소가 있을 시 동일 원소 삭제 ex) [2,3] [2,5] -> [3],[5]

3. reserve의 본인원소를 제외한 -1, +1 여벌 치수를 새 배열(newReserve)로 생성 ex) [3,6]

4. lost 학생과 비교해서 lost 와 동일하면 newReserve원소 제거

5. 전체 학생 수에서 체육복을 얻지못한 학생 수 빼기

 

4번에서

그런데 어떤 기준으로 어떻게 제거해야할 지 감이 오지않았다. 무엇보다도 코드가 너무 길다

다시 생각해보자.

function solution(n, lost, reserve) {
  //  1. 우선 번호 정렬
  const lostArr = lost.sort((a, b) => {
    return a - b;
  });
  const reservetArr = reserve.sort((a, b) => {
    return a - b;
  });

  //2 lost == reserve 동일한 원소가 있을 시 lost&reserve에서 제거
  for (let i = 0; i < lostArr.length; i++) {
    for (let j = 0; j < reservetArr.length; j++) {
      if (lostArr[i] === reservetArr[j]) {
        lostArr.splice(i, 1);
        reservetArr.splice(j, 1);
      }
    }
  }

  //2 체격이 맞아 체육복을 입을 수 있는 학생 수
  //2.1 reserve학생 체육복 치수 나열
  let newReserve = [];
  reservetArr.forEach((num) => {
    if (num === 1) {
      newReserve.push(num + 1);
    } else {
      newReserve.push(num - 1, num + 1);
    }
  });

  //2.2 lost 학생과 비교해서 lost 와 동일하면 newReserve원소 제거

  for (let i = 0; i < lostArr.length; i++) {
    for (let j = 0; j < newReserve.length; j++) {
      if (lostArr[i] === newReserve[j]) {
        lostArr.splice(i, 1);
          lostArr.splice(i, 1);
      }
    }
  }

  //2.3 가능 학생 카운트 1. 학생수에 더하기
  return n - lostArr.length;
}

 

두번째 풀이-> 문제 생김

 

1. 전체학생이 체육복을 다가지고 있다고 생각하자. = 전체학생 체육복 배열 ex) 4명이면 [1,1,1,1]

2. 도난당한 학생들 번호는 0으로 바꾸자 ex) 2번이면 [1,0,1,1]

3. 여벌 체육복 가지고 온 애들은 개수 증가 시키자 ex) 3번이면 [1,0,2,1]

4. 원소 0을 만나면 왼쪽부터, 체육복 줄 수 있는 지 검사하고, 개수 갱신, 오른쪽도 동일하게

5. 원소가 1개 이상인 학생 수 합산

 

function solution(n, lost, reserve) {
// 1. 전체학생이 체육복을 다가지고 있다고 생각하자. = 전체학생 체육복 배열 ex) 4명이면 [1,1,1,1]
  let clothesStatus = new Array(n).fill(1);
  // 2. 도난당한 학생들 번호는 개수를 감소시키자 ex) 2번이면 [1,0,1,1]
  for (let i = 0; i < lostArr.length; i++) {
    --clothesStatus[lost[i] - 1];
  }
  // 3. 여벌 체육복 가지고 온 애들은 개수 증가 시키자 ex) 3번이면 [1,0,2,1]
  for (let i = 0; i < reserveArr.length; i++) {
    ++clothesStatus[reserve[i] - 1];
  }
  // 4. 원소 0을 만나면 왼쪽부터, 체육복 줄 수 있는 지 검사하고, 개수 갱신, 오른쪽도 동일하게
  for (let i = 0; i < n; i++) {
    if (clothesStatus[i] === 0) {
      if (clothesStatus[i - 1] > 1) {
        ++clothesStatus[i];
        --clothesStatus[i - 1];
      }
      if (clothesStatus[i + 1] > 1) {
        ++clothesStatus[i];
        --clothesStatus[i + 1];
      }
    }
  }
  // 5. 원소가 1개 이상인 학생 수 합산
  return clothesStatus.filter((s) => s >= 1).length;
}

대체 왜.

 

문제가 발생하는 이유

 

else if 안쓰고 if써서..//ㅋ

if if의 경우, 왼쪽도 빌려주고 오른쪽도 빌려주고 양쪽 다 빌려주게 된다.

 if (clothesStatus[i - 1] > 1) {
        ++clothesStatus[i];
        --clothesStatus[i - 1];
      }
      if (clothesStatus[i + 1] > 1) {
        ++clothesStatus[i];
        --clothesStatus[i + 1];
      }​

 

더 간단한 풀이

function solution(n, lost, reserve) {
    const clothes = new Array(n).fill(1); // 학생들의 체육복 개수를 저장하는 배열 생성 및 초기화

    // 도난당한 학생들의 체육복 개수 감소
    lost.forEach(student => clothes[student - 1]--);

    // 여벌의 체육복을 가져온 학생들의 체육복 개수 증가
    reserve.forEach(student => clothes[student - 1]++);

    // 체육복 빌려주기
    clothes.forEach((student, index) => {
        if (student === 0) {
            if (clothes[index - 1] === 2) {
                clothes[index - 1]--;
                clothes[index]++;
            } else if (clothes[index + 1] === 2) {
                clothes[index + 1]--;
                clothes[index]++;
            }
        }
    });

    // 수업을 들을 수 있는 학생 수 계산
    const answer = clothes.filter(student => student >= 1).length;

    return answer;
}

 

forEach

: 항목 컬렉션에서 일련의 값을 단계별로 실행(반복)하는 언어 구문

for(let i=0; i<arr.length; i++){
	console.log(i);
}

arr.forEach((i)=>
	console.log(i);
);

 

For vs forEach

가독성

forEach문 : 가독성을 높일 수 있음

for문 : 길고 복잡

 

속도

forEach문 : 값에 직접 접근하지 않고, 배열 요소를 열거자로부터 가져오기 때문에 성능 저하 발생

for문 : 배열 인덱스를 직접 접근하여 값을 가져옴

 

루프 순서

forEach문 : 루프 순서 제어 불가능

for문 : 루프 순서 제어, 인덱스를 증가시키거나 감소시키면서 루프를 실행할 수 있고, 최적화 가능

 

액세스 패턴

forEach문 : 일반적으로 요소를 반복하는 데 더 적합

for문 : 인덱스 변수를 사용해서 요소 접근