[코딩테스트]프로그래머스 - 숫자 야구

Adela·2020년 5월 6일
1

프로그래머스

목록 보기
5/30
post-thumbnail

여러가지 이유가 겹친 것 같다. 결국 멘탈이 와장창 터져버린 오늘 하루..

숫자 야구

문제 설명

숫자 야구 게임이란 2명이 서로가 생각한 숫자를 맞추는 게임입니다.
각자 서로 다른 1~9까지 3자리 임의의 숫자를 정한 뒤 서로에게 3자리의 숫자를 불러서 결과를 확인합니다. 그리고 그 결과를 토대로 상대가 정한 숫자를 예상한 뒤 맞힙니다.

  • 숫자는 맞지만, 위치가 틀렸을 때는 볼
  • 숫자와 위치가 모두 맞을 때는 스트라이크
  • 숫자와 위치가 모두 틀렸을 때는 아웃
    예를 들어, 아래의 경우가 있으면
A : 123
B : 1스트라이크 1볼.
A : 356
B : 1스트라이크 0볼.
A : 327
B : 2스트라이크 0볼.
A : 489
B : 0스트라이크 1볼.

이때 가능한 답은 324와 328 두 가지입니다.
질문한 세 자리의 수, 스트라이크의 수, 볼의 수를 담은 2차원 배열 baseball이 매개변수로 주어질 때, 가능한 답의 개수를 return 하도록 solution 함수를 작성해주세요.

제한사항

질문의 수는 1 이상 100 이하의 자연수입니다.
baseball의 각 행은 [세 자리의 수, 스트라이크의 수, 볼의 수] 를 담고 있습니다.

입출력 예

baseball						return
[[123, 1, 1], [356, 1, 0], [327, 2, 0], [489, 0, 1]]	2

입출력 예 설명

문제에 나온 예와 같습니다.

해결한 코드

function solution(baseball){
	var answer = 0
    var flag = true
    var strike = 0
    var ball = 0
    var num1 = ''
    var num2 = ''
    
    for(var i=123; i<=987; i++){
    	num1 = i.toString() // 정답 후보 123 ~ 987 까지 완전 탐색
        if(num1[0] == num1[1] || num1[1] == num[2] || num[0] == num[2]) continue
        else if (num1[0] == '0' || num1[1] == '0' || num1[0] == '0') continue
        
        flag = true
        
        for(var j=0; j<baseball.length; j++){
        	strike = 0
            	ball = 0
        	num2 = baseball[j][0].toString() // 질문으로 오는 세자리 수 
            
            for(var a=0; a<3; a++){
            	for(var b=0; b<3; b++){
                	if(a == b && num1[a] == num2[b]){ // 질문으로 오는 세자리 수랑 정답 후보랑 자리, 숫자 완전히 일치하면 
                    		strike++ // 스트라이크 추가 
                        	continue // 밑에꺼 무시 
                    	}
                    	if(a != b && num1[a] == num2[b]){ // 숫자는 같은데, 자리가 다르면
                    		ball++ // 볼 추가 
                        	continue
                    	}
                }
            }
            if(strike != baseball[j][1] || ball != baseball[j][2]){ // 질문한 수랑 같이 온 스트라이크, 볼 숫자와 다르면 
            	flag = false // 틀리다는 신호 
                break // 반복문 나가기 
            }
        }
        
        if(flag == true){
        	answer++ // 맞으면 정답 개수 추가 
        }
    }
    return answer
}

문제가 너무 어려워서 멘탈이 나갔다기 보다는, 멘탈이 나갈 타이밍에 이 문제를 봐서 그런 것 같다.
이렇게 생각해서 풀어야 하는 거였구나. 깨달은 문제 ㅜㅜ

알고리즘

  1. 정답이 되는 3자리 숫자는 서로 다른 수 && 1~9사이의 수이다.
    1-1. num1[0], num1[1], num1[2]는 서로 달라야 한다.
    1-2. 0은 있으면 안된다.
    1-3. 따라서 제일 작으면 123, 제일 크면 987이다. 그 사이의 숫자들만 정답이 될 수 있다.
  2. 정답 후보가 질문으로 오는 세자리 수와
    2-1. 숫자, 자리 모두 일치하면 스트라이크++
    2-2. 숫자는 일치하지만 자리는 일치하지 않으면 볼++
  3. 추가한 스트라이크와 볼의 개수가 baseball안의 스트라이크 수와 볼 수와 다르면 false
  4. 같으면 true --> 정답 후보 확정 --> answer 숫자 추가

사실 나는 어떻게 해야 할지 모르겠다는 생각이 가장 컸고 (ㅋㅋㅋㅋ)
다음과 같은 생각으로 풀고자 했다.

나의 알고리즘

  1. 질문으로 오는 세자리수가 스트라이크가 있으면 스트라이크 배열에 넣는다.
  2. 볼이 있으면 볼 배열에 넣는다.
  3. 둘 다 있으면 두 배열 모두에 넣는다.
  4. 스트라이크에 오는 수들 중 같은 자리에 겹치는 애들이 있으면 그 자리 수는 확정이다.
    4-1. ex. strike = [[1,2,3], [3,5,6], [3,2,7]] 이라면,
    4-2. strike[i][0] 자리엔 3이 두개 / strike[i][1] 자리엔 2가 두개
    4-3. 따라서 정답은 무조건 3,2,x 가 될 것이다.
  5. 그럼 이를 토대로 볼 배열에 가서 3,2가 되는 수는 제거하고, 세번째 자리에 오는 숫자도 제거한다.

그러나 이렇게 풀면, ball = [[1,2,3], [4,8,9]] 에서 맨 앞에 있는 1을 어떻게 처리해줘야 할지에 대한 별다른 방안이 없다.

결국 풀지 못했고, 구글링의 도움을 받았다.

완전탐색 문제인 만큼,

  1. (경우의 수가 작은 경우에는) 진짜 123부터 987까지 모든 정답이 되는 수를 다 탐색해보면서 일일이 맞춰가는게 답이 되겠구나

  2. 질문으로 들어온 수에 맞춰 strike와 ball을 계산하고, 이 값이 정답의 strike와 ball의 수와 같은지 맞추면 되겠구나

를 깨달았다.

또 하나의 알고리즘을 알게 되었다. 새로운 계산 방법을 배운 것에 감사한다.

profile
개발 공부하는 심리학도

0개의 댓글