[TIL] 211018

📝 오늘 한 것

  1. 프로그래머스 문제 풀이 - 완주하지 못한 선수 / 두 정수 사이의 합 / 평균 구하기 / 짝수와 홀수 / 체육복

  2. Math.abs() / filter()를 이용해 합집합, 교집합, 차집합 구하는 법


📚 배운 것

1. 프로그래머스 문제 풀이

1) Level 1 문제 풀이

(1) 완주하지 못한 선수

🔎 옛날에 작성했던 풀이

  • 정확도 테스트만 통과하고 효율성 테스트는 0점 맞았던 답안...
function solution(participant, completion) {
  for (let i = 0; i < completion.length; i++) { // 순회
    var index = participant.indexOf(completion[i]); // 선형 검색
    participant.splice(index, 1); // 삭제
  }
  var answer = participant.toString();

  return answer;
}

🔎 수정한 풀이

  • sort()를 이용해 두 배열을 정렬한다.
  • for 루프를 이용해 각 배열의 i번째 요소가 서로 같은지를 확인한다.
  • 다른 것을 찾았다면, 그 요소를 변수 answer에 할당해 반환한다.
function solution(participant, completion) {
  var answer = '';

  participant.sort();
  completion.sort();

  for (let i = 0; i < participant.length; i++) {
    if (participant[i] !== completion[i]) {
      answer = participant[i];
      break;
    }
  }

  return answer;
}

🔎 다른 사람의 풀이 1

  • pop()을 이용해 두 배열의 끝에서 제거한 요소들끼리 비교한 후, 다르다면 이를 반환한다.
function solution (participant, completion) {
  participant.sort();
  completion.sort();
  
  while (participant.length) {
    let participant_pop = participant.pop();
    if (participant_pop !== completion.pop()) {
      return participant_pop;
    }
  }
}

🔎 다른 사람의 풀이 2

forEach()해시 테이블(Hash Table) 이용

  • participant 배열을 해시 테이블로 만든다
  • p 배열의 요소를 key로 하고, 그 value는 1로 한다.
  • 만약 (p 배열의 요소가 중복되어) p 배열의 요소를 key로 하는 value가 이미 존재한다면, 그 value를 1 증가시킨다.
  • completion 배열의 요소를 key로 하여 읽어온 value를 1 감소시킨다. ( = p 배열과 c 배열에 중복되는 요소를 key로 하는 value를 1 감소시킨다.)
  • for in 루프를 이용해 해시 테이블의 value가 1 이상인 key를 찾아 최종적으로 그 key를 리턴한다.
function solution(participant, completion) {
  let hash = [];
  
  participant.forEach(name => {
    hash[name] = hash[name] ? hash[name] + 1 : 1        
  })

  completion.forEach(name => {
    hash[name] = hash[name] - 1
  })

  for (var name in hash) {
    if (hash[name] >= 1) {
      return name
    }
  }
}

(2) 두 정수 사이의 합

🔎 처음 작성한 풀이

  • 정확도 테스트는 통과했고 효율성 테스트는 없었지만 효율성이 안 좋은 풀이다
function solution(a, b) {
  const nums = [];

  if (a < b) {
    for (let i = a; i <= b; i++) {
      nums.push(i);
    }   
  } else if (a > b) {
    for (let i = b; i <= a; i++) {
      nums.push(i);
    }   
  } else {
    return a;
  }

  return nums.reduce((prev, curr) => prev + curr, 0);
}

🔎 수정한 풀이

  • Math.min()과 Math.max() 사용
  • reduce() 대신 sum 변수를 이용
function solution(a, b) {
  if (a === b) {
    return a;
  }

  let sum = Math.min(a, b);    
  for (let i = Math.min(a, b) + 1; i <= Math.max(a, b); i++) {
    sum = sum + i;
  }
  return sum;
}

🔎 다른 사람의 풀이

  • Math.abs() 이용

    주어진 숫자의 절대값을 반환한다
    ex) console.log(Math.abs(4 - 9)); // 5

function solution(a, b) {
  return (a + b) * (Math.abs(b - a) + 1) / 2;
}

(3) 평균 구하기

🔎 내가 작성한 풀이

function solution(arr) {
  return arr.reduce((prev, curr) => prev + curr, 0) / arr.length;
}

(4) 짝수와 홀수

🔎 내가 작성한 풀이

function solution(num) {    
  if (num % 2 === 0) {
    return 'Even';
  } else {
    return 'Odd';
  }
}

🔎 다른 사람의 풀이

  • 조건부 삼항 연산자 이용
function solution(num) {    
  return num % 2 === 0 ? 'Even' : 'Odd';
}

(5) 체육복

🔎 처음 작성한 풀이

  • 각각 lost와 reserve에서 체육복 여벌을 가지고 있으면서 동시에 한 벌을 도난당한 학생들 즉, lost와 reserve의 교집합을 제거한 후, lost와 reserve 배열에 담긴 요소(학생들 번호)들을 조건을 고려해 비교하고자 했다.

  • 테스트 케이스는 통과했으나, 실제 채점 시 정확도 테스트에서 55점 맞은 답안...이었는데 다시 하니까 85점 나온다. 뭐지? 어쨌든 틀린 풀이다.

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

  const lostCount = lost.length;
  const reserveCount = reserve.length;

  const intersection = [];

  for (let i = 0; i < lost.length; i++) {
    for (let j = 0; j < reserve.length; j++) {
      if (lost[i] === reserve[j]) {
        intersection.push(lost[i]);
        lost.splice(i, 1);
        reserve.splice(j, 1);
        break;
      }
    }
  }

  
  let lentCount = 0;

  for (let i = 0; i < reserve.length; i++) {
    for (let j = 0; j < lost.length; j++) {
      if (reserve[i] === lost[j] - 1 || reserve[i] === lost[j] + 1) {
        lentCount++;
        lost.splice(j , 1);
        break;
      }
    }
  }

  const rest = n - (lostCount + reserveCount - intersection.length);
  answer = rest + reserveCount + lentCount;
  return answer;
}

🔎 두 번째 작성한 풀이

  • 테스트 케이스를 하나씩 추가해서 오류를 찾았다. 교집합을 구하는 for 루프에서 splice를 이용해 lost 배열의 중간 요소를 계속 제거하는 부분이 문제였다. 바깥 루프가 다음 루프를 돌 때 i는 이전에 비해 똑같이 1이 증가했지만, 실제 lost 배열에서는 이전 요소의 다음 요소가 아니라 다다음 요소가 잡히게 된다. 이는 이전 루프에서 splice에 의해 그 루프에서 잡혔던 요소를 제거했기 때문이다.

  • 또한, splice로 인해 lost 배열과 reserve 배열을 제거했어도 lentCount를 증가시키는 중첩 루프에서 사용되는 lost 배열과 reserve 배열은 당연하게도 solution 함수의 매개변수로 전달된 배열들 그대로였기 때문에 의도했던 대로 비교가 되지 않았다.

  • 각각 lost 배열과 reserve 배열에서 교집합을 제거하는 데 중첩 루프를 사용하니까 블록 스코프 안에서만 변화가 적용돼서 다음 코드에서 이어서 쓸 수가 없었다. 다른 방법이 있나 검색해보다 신세계 발견. [javascript] 배열 값 중복제거, 배열합치기 참고

  • 맞을 줄 알았는데 90점이 나왔다. 뭐가 문제일까.

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

  const lostCount = lost.length;
  const reserveCount = reserve.length;

  // lost + reserve
  const sum = lost.concat(reserve);

  // 교집합
  const intersection = sum.filter((item, index) => sum.indexOf(item) !== index);

  // 차집합 : lost - (lost ∩ reserve)
  const restLost = lost.filter(x => !intersection.includes(x));

  // 차집합 : reserve - (lost ∩ reserve)
  const restReserve = reserve.filter(x => !intersection.includes(x));


  // 체육복을 빌린 학생 수
  let lentCount = 0;

  for (let i = 0; i < restReserve.length; i++) {
    for (let j = 0; j < restLost.length; j++) {
      if (restReserve[i] === restLost[j] - 1 || restReserve[i] === restLost[j] + 1) {
        lentCount++;
        restLost.splice(j , 1);
        break;
      }
    }
  }


  // 본인 체육복만 가져와서 본인이 입는 학생 수 (도난x, 여별x)
  const rest = n - (lostCount + reserveCount - intersection.length);

  // '전체 학생 수 n - 체육복을 못 빌린 학생 수'와 같다
  answer = rest + reserveCount + lentCount;

  return answer;
}

🔎 세 번째 작성한 풀이

  • 맨 처음에 lost 배열과 reserve 배열을 오름차순으로 정렬해주는 코드를 추가했다.

  • 드디어 100점이다.

function solution(n, lost, reserve) {
  lost.sort((a, b) => a - b);
  reserve.sort((a, b) => a - b);
  
  const sum = lost.concat(reserve);
  const intersection = sum.filter((item, index) => sum.indexOf(item) !== index);
  const restLost = lost.filter(x => !intersection.includes(x));
  const restReserve = reserve.filter(x => !intersection.includes(x));

  const lostCount = lost.length;
  const reserveCount = reserve.length;
  let lentCount = 0;

  for (let i = 0; i < restReserve.length; i++) {
    for (let j = 0; j < restLost.length; j++) {
      if (restReserve[i] === restLost[j] - 1 || restReserve[i] === restLost[j] + 1) {
        lentCount++;
        restLost.splice(j , 1);
        break;
      }
    }
  }

  const rest = n - (lostCount + reserveCount - intersection.length);
  return rest + reserveCount + lentCount;
}

✨ 내일 할 것

  1. 프로그래머스 문제 풀이

좋은 웹페이지 즐겨찾기