<중복순열>
rockPaperScissors
문제
가위바위보 게임은 2인 이상의 사람이 동시에 '가위, 바위, 보'를 외치고 동시에 가위, 바위 또는 보 중에서 한 가지를 의미하는 손 모양을 내밀어 승부를 결정짓는 게임입니다. 세 판의 가위바위보 게임을 할 경우, 한 사람은 세 번의 선택(예. 가위, 가위, 보)을 할 수 있습니다. 세 번의 선택으로 가능한 모든 경우의 수를 구하는 함수를 작성합니다.
입력
없음
출력
2차원 배열(arr[i]
)을 리턴해야 합니다.
arr[i]
는 전체 경우의 수 중 한 가지 경우(총 세 번의 선택)를 의미하는 배열입니다.
arr[i]
는 'rock', 'paper', 'scissors' 중 한 가지 이상을 요소로 갖는 배열입니다.
arr[i].length
는 3
주의사항
최종적으로 리턴되는 배열의 순서는 가중치 적용 정렬(Weighted Sort)을 따릅니다.
중요도는 'rock', 'paper', 'scissors' 순으로 높습니다.
쉽게 생각해 올림픽 순위 결정 방식을 참고하면 됩니다.
금메달('rock')이 은메달('paper')보다 우선하고, 은메달('paper')이 동메달('scissors')보다 우선합니다.
function rockPaperScissors (rounds) {
// TODO: 여기에 코드를 작성합니다.
rounds = rounds || 3;
const game = ['rock','paper','scissors'];
const outcome = [];
let permutate = function(roundsToGo, playedSoFar){
//base case
if(roundsToGo === 0){
outcome.push(playedSoFar);
return;
}
//반복 case
for(let i=0; i<game.length; i++){
const currentPlay = game[i];
permutate(roundsToGo-1, playedSoFar.concat(currentPlay));
}
}
permutate(rounds, []);
return outcome;
};
<순열>
새로운 치킨 소스 레시피
문제
'승승장구 치킨집'의 비결은 소스에 있다. 수많은 타사 브랜드 치킨집들이 승승장구 치킨집의 소스 비결을 알아내려고 했으나 빈번히 포기했다. 그 이유는 5대째 내려오는 '비밀의 승승장구 치킨 소스 비율 레시피'는 사장님만 알고 있기 때문이다. 최근, 누리꾼 사이에서 이 레시피의 일부분을 발췌했다는 소문을 듣게 되었다.
그 소문은 다음과 같다.
N 가지의 재료 중에 단 M 가지만을 사용하여 조합한 모든 경우의 수 중 하나이다.
재료는 0과 1로만 이루어진 숫자로 암호화가 되어 있고, 항상 1로 시작하며 복호화를 할 수 없다.
단, 0이 3개 이상인 재료는 상한 재료이기 때문에 제외한다.
재료의 순서에 따라 맛이 달라지기 때문에, 재료를 넣는 순서가 다르다면 다른 레시피이다.
이 소문을 참고하여 '비밀의 승승장구 치킨 소스'가 될 수 있는 경우의 수를 모두 반환하는 함수를 작성하세요.
입력
인자 1: stuffArr
Number 타입의 재료를 담은 배열
요소는 0과 1로만 이루어진 숫자이며, 항상 1로 시작합니다.
요소는 중복될 수 없습니다.
요소의 길이는 20 이하입니다.
배열의 길이는 2 이상 10 이하입니다.
ex)[111, 110, 1010, 10, 10110]
인자 2: choiceNum
Number 타입의 1 이상 stuffArr 길이 이하의 자연수
재료를 선택할 수 있는 수를 뜻합니다.
ex) 2
출력
Number 타입을 반환해야 합니다.
stuffArr가[1, 10, 11000, 1111]
이고, choiceNum은 2라면 사용 가능한 재료는[1, 10, 1111]
입니다. 조합할 수 있는 경우의 수는 6 가지입니다.
주의사항
만약, 주어진 재료 모두 사용할 수 없다면 빈 배열[]을 반환해야 합니다.
만약, 사용할 수 있는 재료가 choiceNum보다 작다면 빈 배열[] 을 반환해야 합니다.
조합 및 요소는 작은 숫자 -> 큰 숫자로 정렬합니다.
예시로[1, 10, 11000, 1111]
이 요소로 들어왔다면, 0이 세 개인 11000을 제외하고[1, 10, 1111]
순서가 되어야 하며,
[ [1, 10], [1, 1111], [10, 1], [10, 1111], [1111, 1], [1111, 10] ]
을 반환해야 합니다.
function newChickenRecipe(stuffArr, choiceNum){
//싱싱한 재료만 담을 배열
//0이 세개 이상인 재료는 상한 것이므로 제외시키기 위해
//문자열로 바꾸고 분할해서 배열로 담은뒤 "0"만 새로운 배열에 담았을때
//"0"의 갯수가 3개미만이면 싱싱한 재료이므로 freshArr에 저장
let freshArr = [];
for(let i=0;i<stuffArr.length;i++){
const element = String(stuffArr[i]).split('').filter(el=>el==="0");
if(element.length<3){
freshArr.push(stuffArr[i]);
}
}
//조합 및 요소는 작은숫자->큰숫자로 정렬되어야 하므로 오름차순으로 정렬
freshArr.sort((a,b)=>a-b);
//엣지 케이스 처리
if(freshArr.length===0 || freshArr.length<choiceNum) {return []}
//레시피 초기화
let result = [];
//freshArr를 상대로 순열 구하기
const permutation = (arr, bucket, n) => {
//재귀 종료조건
if(n===0){
result.push(bucket);
return;
}
for(let i=0;i<arr.length;i++){
//중복되는 것을 제외시키기 위해 첫번째 요소를 저장하고
//배열을 복사하여 원본을 유지하고
//복사한 배열에서 이미 사용한 요소를 제거한다
const choice = arr[i];
const sliceArr = arr.slice();
sliceArr.splice(i,1);
permutation(sliceArr,bucket.concat(choice),n-1);
}
}
permutation(freshArr, [], choiceNum);
return result;
}
<조합>
블랙잭은 지겨워
문제
평범한 블랙잭 게임에서 수시로 패배하자 흥미가 떨어진 김코딩은 박타짜에게 게임룰을 변형하여 새로운 카드 놀이를 해 볼 것을 제안합니다.
새로운 룰은 다음과 같습니다.
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이하의 자연수입니다.
function boringBlackjack(cards) {
//카드들 중 3개를 뽑아 합한 숫자들이 소수인지 확인하고, 소수인 것들의 갯수를 구해야한다
//세장의 카드의 합이 중요한 것이므로 카드의 뽑힌 순서는 중요하지 않고 (===>조합)
//소수인지 확인하는 함수를 만들어 참이면 count를 1씩 증가한다
//소수의 갯수를 의미하는 count를 리턴한다
const cardsLen = cards.length;
let count = 0;
//한번 뽑은 카드는 또 뽑을 수 없으므로 처음으로 0번째 인덱스 카드를 뽑았다고 할때
//두번째 뽑을 수 있는 카드는 이미 뽑은 0번째 카드를 제외한 j(i+1)번째 인덱스부터 뽑을 수 있고
//세번째 뽑을 수 있는 카드는 이미 뽑은 두 개의 카드를 제외한 k(j+1)번쨰 인덱스부터 뽑을 수 있다
for(let i=0;i<cardsLen;i++){
for(let j=i+1;j<cardsLen;j++){
for(let k=j+1;k<cardsLen;k++){
const sum = cards[i]+cards[j]+cards[k];
if(isPrime(sum)){
count++;
}
}
}
}
//아래처럼 함수선언식으로 쓰면 호이스팅되어 함수선언 위치가 호출위치보다 아래여도 잘 작동하지만
//const isPrime = ()=>{}처럼 함수표현식으로 쓰면 호이스팅되지 않아 cannot access before initialization이라고 뜬다.
function isPrime(val){
for(let i=2;i<val;i++){
if(val%i===0){return false}
}
return true;
}
return count;
}