새소식

프론트엔드 공부/자료구조 & 알고리즘

[조합] 블랙잭은 지겨워

  • -

블랙잭은 지겨워

문제

평범한 블랙잭 게임에서 수시로 패배하자 흥미가 떨어진 김코딩은 박타짜에게 게임룰을 변형하여 새로운 카드 놀이를 해 볼 것을 제안합니다.

새로운 룰은 다음과 같습니다.

1. 숫자로 이루어진 카드를 여러 장 받습니다.

2. 3장씩 카드를 고르고, 3장에 적힌 숫자들의 합이 소수인지 확인합니다.

3. 받아든 카드로 만들 수 있는 소수의 개수가 많은 사람이 이기게 됩니다.

예로, [1, 2, 3, 4]라는 카드를 받았을 때 만들 수 있는 숫자는 6, 7, 8, 9이고, 소수는 7 하나이기 때문에 가지고 있는 소수의 개수는 1개입니다.

[2, 3, 4, 8, 13]라는 카드를 받았을 때 만들 수 있는 숫자는 9, 13, 18, 14, 19, 23, 15, 20, 24, 25이고, 소수는 13, 19, 23 총 3개이기 때문에 가지고 있는 소수의 개수는 3개입니다.

게임을 진행하기 전에 소수에 대해 아무런 지식이 없는 박타짜는 게임을 며칠 미룬 뒤, 게임의 룰을 따르는 함수를 만들기로 했습니다.

소수에 약한 박타짜를 도와 여러 장의 카드 중 세 장씩 조합해 소수가 되는 경우의 수를 리턴하는 함수를 완성해 주세요.

입력

인자 1

  • cards: Array 3개 이상 50개 이하의 카드가 숫자로 들어 있는 배열

출력

  • Number 타입을 리턴해야 합니다.

주의사항

  • cards 에는 중복된 숫자의 카드는 들어있지 않습니다.
  • 각 카드에 적힌 수는 1이상 1,000이하의 자연수입니다.

입출력 예시

let output = boringBlackjack([1, 2, 3, 4]);
console.log(output); // 1

let output = boringBlackjack([2, 3, 4, 8, 13]);
console.log(output); // 3

문제 풀이

function boringBlackjack(cards) {
  // cards 50이하의 숫자배열을 인자로 받습니다.
  // 그중 3개 뽑아서 나오는 경우의 수 구하기

  // 3중 for문을 이용해 3개의 숫자를 뽑는 모든 경우의 수를 구합니다.
  let primeCount = 0;
  for (let i = 0; i < cards.length; i++) {
    for (let j = i + 1; j < cards.length; j++) {
      for (let k = j + 1; k < cards.length; k++) {
        let result = cards[i] + cards[j] + cards[k];
        // 뽑은 3개의 숫자의 합이 소수인지 판단합니다.
        if (isPrime(result)) {
          primeCount++;
        }
      }
    }
  }

  // 소수인지 여부를 판단하는 함수입니다.
  function isPrime(num) {
    // 주어진 숫자의 제곱근까지 for문을 실행해 나누어지는 수가 있는지 판단합니다.
    for (let i = 2; i <= Math.floor(Math.sqrt(num)); i++) {
      if (num % i === 0) {
        // 나누어지는 수가 있을 경우, 소수가 아니므로 false를 반환합니다.
        return false;
      }
    }
    // 주어진 수가 소수인 경우 true를 반환합니다.
    return true;
  }

  // 뽑은 3개의 숫자의 합이 소수인 경우의 수를 반환합니다.
  return primeCount;
}

위 코드는 함수 내부에 주석을 추가하여 자세한 설명을 담았습니다. 함수는 cards 배열에서 3개의 숫자를 뽑은 후, 그 숫자들의 합이 소수일 경우의 수를 구하는 것이 목적입니다.

먼저, 배열에서 3개의 숫자를 뽑아야 하므로, 3중 for문을 이용합니다. 이때 각 for문은 배열의 index 값을 이용하여 적절하게 연산합니다. 각 for문은 다음과 같은 역할을 합니다.

  • 첫번째 for문 : 가장 앞쪽에 있는 숫자를 선택합니다.
  • 두번째 for문 : 첫번째 숫자 이후 앞쪽의 숫자를 선택합니다.
  • 세번째 for문 : 두번째 숫자 이후 앞쪽의 숫자를 선택합니다.

숫자를 선택한 후, 이들의 합계를 구하고, 이것이 소수인지 여부를 판단합니다. 소수를 확인하는 것은 isPrime 함수가 맡고 있습니다. 이 함수는 for문을 이용하여 주어진 숫자를 2부터 제곱근까지 나누어서 나머지가 0인 수가 있는지를 확인하여 소수인지 여부를 판단하는 것입니다. 마지막으로, 소수인 경우를 세는 primeCount를 반환합니다.

레퍼런스 코드

function boringBlackjack(cards) {
  let count = 0;

    // 1. cards 에서 카드 3장 뽑기
    let length = cards.length;
    // 카드 뽑는 방식은 첫 카드를 cards 의 0번 index 부터 고정해 놓고 1씩 뒤로 옮겨간다
    for (let i = 0; i < length; i++) {
    // 두 번째 카드의 인덱스는 첫 카드 + 1에서 시작해야 하고
      for (let j = i + 1; j < length; j++) {
    // 세 번째 카드의 인덱스는 두 번째 카드 + 1에서 시작해야 한다 
        for (let k = j + 1; k < length; k++) {
          const number = cards[i] + cards[j] + cards[k];
          // 세 카드의 합이 소수이면 경우의 수 + 1
          if (isPrime(number)) count++;
        }
      }
    }
  
    //2. 소수 판별
    function isPrime(number) {
    // 2부터 비교하기 시작해서 나누어 떨어지는 수가 있으면 소수가 아니다
    // for 문 조건을 number/2 로 해도 되는 이유는 i > number/2 가 되면 몫이 절대 0이 될수 없기 때문에
    // number/2 까지만 비교해 보아도 소수 판별이 가능하다
      for (let i = 2; i < number/2; i++) {
        if (number % i === 0) return false;
      }
      return true;
    }
  
    return count;
}

'프론트엔드 공부 > 자료구조 & 알고리즘' 카테고리의 다른 글

[순열] 새로운 치킨 소스 레시피  (0) 2023.04.06
[중복순열] 가위바위보  (0) 2023.04.06
[구현] 보드 게임  (0) 2023.04.05
[Greedy] 편의점 알바  (0) 2023.04.05
[Greedy] 짐 나르기  (0) 2023.04.05
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.