(Swift) Programmers 두 원 사이의 정수 쌍

SteadySlower·2023년 7월 3일
0

Coding Test

목록 보기
269/298

문제 링크

처음 풀이 😅

문제 풀이 아이디어

처음에 문제를 풀 때는 문제의 조건에 맞게 정직하게(?) 큰 원 안에 있는 점을 모두 구하고, 작은 원 안에 있는 점을 모두 구하고 그 둘을 뺐습니다. 심지어 작은 원의 경계에 있는 점들은 모두 들어야 가야하기 때문에 작은 원의 경계 위에 있는 점을 다시 구해서 더 해주어야 했습니다.

결국 아래와 같은 길고 지저분한 코드가 나올 수 밖에 없었네요. 참고는…. 말아주세요.

코드

import Foundation

func solution(_ r1:Int, _ r2:Int) -> Int64 {
    
    // 1사분면만 센 다음에 4를 곱한다.
    func countDots(_ r: Int) -> Int {
        var result = 0

        let dr = Double(r)
        for x in 0...r {
            let x = Double(x)
            let y = Int(sqrt(pow(dr, 2) - pow(x, 2)))
            result += y + 1
        }
        
        // 4를 곱했을 때 겹치는 부분
            // 1. 원점 3번 겹침
            // 2. 각 사분면의 경계면 2번씩 겹침 (경계면의 길이 = 2r)
        let overlap = 3 + r * 4

        return result * 4 - overlap
    }
    
    // 원의 경계선에 위치한 점의 갯수를 구하는 함수
    func countEdgeDots(_ r: Int) -> Int {
        var result = 0
        let dr = Double(r)
        // x == r, -r일 때는 각각 경계선의 점이 1개 -> (r, 0), (-r, 0)
            // 따라서 마지막에 2를 더하고 반복문에서는 제외
        for x in (-r + 1)...(r - 1) {
            let x = Double(x)
            let y = sqrt(pow(dr, 2) - pow(x, 2))
            // y가 정수인지 확인 (버림한 값 == 원래 값)
            // 정수로 확인되면 (x, y), (x, -y)로 점이 2개이므로 2를 더함
            if y - Double(Int(y)) == 0 { result += 2 }
        }
        return result + 2
    }

    return Int64(countDots(r2) - countDots(r1) + countEdgeDots(r1))
}

개선된 풀이🏃‍♂️

문제 풀이 아이디어

개선된 풀이 입니다. 일단은 1사분면의 점의 갯수만 구한 후 x4 합니다. 다만 y축 위, 즉 x값이 0일 때의 점의 갯수를 세지는 않습니다. 이렇게 하면 x4를 했을 때 x축, y축이 겹쳐서 빼줘야 하는 수고를 덜 수 있습니다. 즉, 각 사분면의 갯수를 셀 때 x축, y축 중 하나의 축 위에 위치한 점의 갯수만 세는 것입니다.

x값이 1 ~ r2일 때 큰 원, 작은 원의 높이를 각각 구합니다. 다만 작은 원의 반지름은 x값 보다 작을 수 있으므로 그런 경우 0으로 처리합니다.

(정수, 정수)의 좌표만 처리해야 하므로 큰 원의 높이는 내림을 하고 작은 원의 높이는 올림을 하여야 빼주면 됩니다. 다만 작은 원의 높이가 0인 경우에는 (정수, 0)인 점까지 포함해야 하므로 계산을 용이하게 하기 위해서 작은 원의 높이를 올림하는 것이 아니라 반올림 이후에 1을 더해주는 방법을 사용합니다.

코드

import Foundation

func solution(_ r1:Int, _ r2:Int) -> Int64 {
    let dr1 = Double(r1)
    let dr2 = Double(r2)

    var result = 0.0

    // x축 1 ~ r2까지 점의 갯수 구하기
        // x = 0일 때를 빼야지 마지막에 x4를 했을 때 겹치는 부분이 없음
    for x in 1...r2 {
        let dx = Double(x)
        // 작은 원의 경우: x가 반지름 보다 작을 때만 높이를 구함 (아니면 0)
        let y1 = dr1 - dx > 0 ? sqrt(pow(dr1, 2) - pow(dx, 2)) : 0
        // 큰 원의 높이
        let y2 = sqrt(pow(dr2, 2) - pow(dx, 2))
        // 큰 원의 높이는 내림
        // 작은 원의 높이는 반올림 후 -1
            // 원래는 올림을 하는 것이 맞지만 y1이 0인 경우 예외처리를 용이하게 하기 위함
        result += floor(y2) - (ceil(y1) - 1)
    }

    return Int64(result * 4)
}
profile
백과사전 보다 항해일지(혹은 표류일지)를 지향합니다.

0개의 댓글