(Swift) 백준 2503 숫자 야구

SteadySlower·2022년 6월 4일
0

Coding Test

목록 보기
55/305

2503번: 숫자 야구

문제 접근 아이디어

  1. 주어진 민혁의 물음, 영수의 대답으로 정답을 역으로 유추하는 것은 너무 어려운 일입니다.
  2. 하지만 어떤 임의의 숫자에 스트라이크와 볼 갯수를 구하는 것은 쉬운 일입니다.
  3. 그렇다면 모든 가능한 숫자의 스트라이크의 볼 갯수를 구해서 물음 - 대답과 비교하는 것은 어떨까요?
    1. 마침 모든 가능한 숫자는 900개가 채 안됩니다. (중복 숫자가 안되고 0이 들어가도 안되니 훨씬 적을 것입니다.)
    2. 브루탈 포스를 활용해서 문제를 풀어봅시다!

💡  사람이 푸는 문제라면 역으로 유추하는 것이 쉽습니다. 하지만 계산 속도가 빠른 컴퓨터가 해결해야 하는 문제라면 일일히 따져보는 것이 더 쉬워집니다.

풀이

//✅ 숫자 야구에 유효한 숫자인지 검증하는 extension (중복 숫자 없음 + 0 없음)
extension Int {
    func checkIfValid() -> Bool {
        let array = String(self).map { Int(String($0))! }
        let noZero = array.contains(0) ? false : true //👉 0이 없는지
        let noOverlap = Set(array).count != array.count ? false : true //👉 겹치는 숫자가 없는지
        return noZero && noOverlap //👉 두 개다 true일 때만 true를 반환
    }
}

//✅ a, b를 비교해서 strike, ball을 얻는 함수
func getAns(a: Int, b: Int) -> (Int, Int) {
    let aArray = String(a).map { Int(String($0))! }
    let bArray = String(b).map { Int(String($0))! }
    var strike = 0
    var ball = 0
    
    for i in 0..<3 { //👉 자릿수를 모두 순회하면서
        guard aArray.contains(bArray[i]) else { continue } //👉 b의 숫자가 a에 있는지 확인
        if i == aArray.firstIndex(of: bArray[i]) { //👉 자릿수까지 같으면 strike
            strike += 1
        } else { //👉 자릿수는 다르면 ball
            ball += 1
        }
    }
    
    return (strike, ball)
}

//✅ 어떤 숫자 n이 민혁-영수의 물음-대답과 일치하는 지 확인하는 함수
func checkIfResult(n: Int) -> Bool {
    for i in 0..<N { //👉 모든 물음-대답을 순회하면서
        let ans = getAns(a: n, b: questions[i])
        if ans != ansArray[i] { //👉 하나라도 대답이 동일하지 않으면 false
            return false
        }
    }
    return true //👉 모두 동일하면 true
}

//✅ 입력 받기
let N = Int(readLine()!)!
var questions = [Int]()
var ansArray = [(Int, Int)]()

for _ in 0..<N {
    let input = readLine()!.split(separator: " ").map { Int(String($0))! }
    questions.append(input[0])
    ansArray.append((input[1], input[2]))
}

//✅ 가능한 경우의 수를 넣어두는 배열
var result = [Int]()

//✅ 가능한 모든 3자리 정수를 순회
for n in 123...987 {
    guard n.checkIfValid() == true else { continue } //👉 숫자야구에 유효한 숫자이고
    if checkIfResult(n: n) { //👉 모든 물음 - 대답에 일치하면
        result.append(n) //👉 경우의 수 배열에 넣음
    }
}

print(result.count)
  1. 먼저 해당 정수가 숫자 야구 게임의 조건을 만족하는지 확인하는 extension을 만들었습니다.
    1. 파이썬으로 풀 때는 1 ~ 9까지의 숫자로 3의 길이를 가지는 순열로 만족하는 정수들만 구할 수 있었으나 스위프트는 순열을 직접 구현해야 합니다.
    2. 따라서 이렇게 정수를 직접 검증하는 편이 더 빠른 방법입니다.
  2. 두 숫자를 비교해서 스트라이크와 볼 갯수를 반환하는 함수를 만듭니다.
    1. 튜플을 활용했습니다.
  3. 어떤 숫자 n이 모든 물음 - 대답의 쌍과 결과가 일치하는지 확인하는 함수입니다.
    1. 해당 함수에서 true를 반환하면 영수가 생각하고 있을 가능성이 있는 답이 됩니다.
  4. 입력을 받습니다.
    1. 대답의 strike와 ball의 갯수는 마찬가지로 튜플을 활용합니다.
  5. 숫자야구에서 사용이 가능한 3자릿수 정수를 모두 순회해서 정답을 구합니다.
    1. 중복이 없으므로 최소 123 ~ 987로 범위를 좁힐 수 있습니다.
profile
백과사전 보다 항해일지(혹은 표류일지)를 지향합니다.

0개의 댓글