프로그래머스 | 동선 겹침

chaen·2024년 2월 7일
post-thumbnail

📌 문제

독감에 걸린 사람 infected와 00 건물에서 함께 있었던 사람들의 번호를 오름차순으로 추출하세요. 00 건물의 출입기록은 history이며, 사람이 들어올 땐 양수가, 나갈 땐 음수가 기록됩니다.

출력 예시
history = [1, 3, 2, -3, -1, 4, -2, -4, 2, 5, -2]
infected = 2
정답: [1, 3]

  • 사람들은 횟수에 제약없이 여러 번 출입할 수 있습니다.
  • 동선이 겹치는 사람이 없을 경우 빈 배열을 출력합니다.

✨ 해결 방법

isInfected라는 상태를 하나 설정하고, 배열을 계속 순회하면서 infected가 나오기 전까지는 무시, 나오고 나서부터는 사람들의 번호 모음인 배열 infectors에 추가, 다시 -isfected가 나오면 추가를 중단하는 과정을 반복합니다.

이 과정은 infectors를 배열로 설정하고 배열 메서드인 pop을 이용하여infected인 사람을 배열에 넣지 않되, 대신 나중에 음수와 양수로 반복된 중복을 거르는 과정을 수행하는 한 가지 방법이 있고,
또는 처음부터 set으로 설정하여 중복을 받지 않되, infected 본인까지 함께 배열에 받은 후 나중에 infected를 다시 삭제하는 방법이 있습니다.

두 코드는 모두 효율적이고 가독성이 좋기 때문에 주관적인 선호도에 따라 선택 가능합니다.

💻 solution 1

function solution(history, infected) {
    let infectors = [];
    let isInfected = false;
  
    for (let i = 0; i < history.length; i++) {
      if (history[i] === infected) {
        isInfected = true;
        continue; // 현재 infected는 포함하지 않도록 skip
      }
  
      if (isInfected) {
        infectors.push(Math.abs(history[i]));
  
        if (history[i] === -infected) {
          isInfected = false; // -infected가 나오면 false로 변경
          infectors.pop(); // -infected는 배열에 포함시키지 않음
        }
      }
    }

    if (infectors.length === 0) {
        return [];
      }
    
    let set = Array.from(new Set(infectors));
    return set.sort((a, b) => a - b);
  }

infectors를 배열로 받는 방법입니다.

infected 본인을 배열로 추가하지 않기 위해, 배열을 순회하다가 infected를 만나면 상태만 바꾼 후 일단 스킵시킵니다. 그 다음 사람부터, 만약 바뀐 상태 (isInfected ===true) 라면 infectors에 추가가 됩니다. 이때 추가는 입장과 퇴장 상관없이 일단 절대값으로 추가됩니다.

그 상태가 지속되다가 다시 -infected, 즉 infected가 퇴장하게 되면 상태를 바꾸고 배열을 멈춥니다. 일단 -infected도 배열에 추가되었기 때문에, pop()을 통해 마지막 요소를 없애주는 과정이 필요합니다.

만약 동선이 겹치는 사람이 없다면, 빈 배열을 반환하며, 그게 아니라면 set으로 변환하여 양수와 음수의 중복을 하나로 합친 후 다시 배열화합니다.

문제에서는 오름차순으로 출력하라고 했으므로, sort를 통해 오른차순으로 바꾼 것을 출력합니다.

💻 solution 2

function solution(history, infected) {
    let answer = [];
    let infectors = new Set();
    let isInfected = false;
  
    for (let i = 0; i < history.length; i++) {
      if (history[i] === infected) {
        isInfected = true;
      }

      if (isInfected){
        if (history[i] === -infected) {
            isInfected = false;
          } else{
            infectors.add(Math.abs(history[i]));
          }
      }
    }

    // 배열에서 infected와 -infected를 제외한 값만 남기기
    answer = Array.from(infectors).filter(number => number !== infected).sort((a, b) => a - b);
    return answer;
    
  }

infectorsset으로 선언하는 방법입니다.

우선 answer을 만들어 빈 배열로 선언합니다. 이는 동선이 겹치는 사람이 없을 경우의 예외를 방지합니다.

똑같이 inInfected로 상태를 선언하고, 감염자 본인 여부와 상관 없이, for 문을 순회하며 감염자가 나온 이후부터 상태를 바꾼 후 set에 추가할 겁니다. isInfectedtrue일 땐 우선 -infected 인지 검사하고, 해당 경우엔 상태 변화를, 아닐 경우엔 해당 값의 절대 값을 set에 추가합니다.

감염자 본인도 set에 추가되었으므로, 감염자를 추출하는 과정이 필요하며, 오름차순으로의 정렬도 필요합니다. 다만 filtersort는 모두 배열의 메서드이므로, 우선 infectors를 배열화 시킨 후 진행합니다. 이 과정을 answer에 담고 결과를 반환합니다.

0개의 댓글