Archive/Questions

[programmers/Swift] 교점에 별 만들기

Marco 2022. 5. 22. 19:33
728x90

programmers.co.kr - 코딩테스트연습 - Lv.2 - 위클리 챌린지 - 교점에 별 만들기

 

코딩테스트 연습 - 교점에 별 만들기

[[2, -1, 4], [-2, -1, 4], [0, -1, 1], [5, -8, -12], [5, 8, 12]] ["....*....", ".........", ".........", "*.......*", ".........", ".........", ".........", ".........", "*.......*"] [[0, 1, -1], [1, 0, -1], [1, 0, 1]] ["*.*"] [[1, -1, 0], [2, -1, 0], [4, -

programmers.co.kr

Constraints :

  • line의 세로(행) 길이는 2 이상 1,000 이하인 자연수입니다.
    • line의 가로(열) 길이는 3입니다.
    • line의 각 원소는 [A, B, C] 형태입니다.
    • A, B, C는 -100,000 이상 100,000 이하인 정수입니다.
    • 무수히 많은 교점이 생기는 직선 쌍은 주어지지 않습니다.
    • A = 0이면서 B = 0인 경우는 주어지지 않습니다.
  • 정답은 1,000 * 1,000 크기 이내에서 표현됩니다.
  • 별이 한 개 이상 그려지는 입력만 주어집니다.

 

Solution.swift :

//
//  Created by Yongwoo Marco on 2022/05/18.
//  Copyright © 2022 Yongwoo Marco Kim. All rights reserved.
//

func solution(_ line:[[Int]]) -> [String] {
    var coordinates = [Int: [Int]]()
    var maxX = Int.min, maxY = Int.min, minX = Int.max, minY = Int.max
    
    
    func makeCoordinates(arr1: [Double], arr2: [Double]) {
        let deno = arr1[0] * arr2[1] - arr1[1] * arr2[0]
        guard deno != 0 else { return }
        
        let x = (arr1[1]*arr2[2] - arr1[2]*arr2[1]) / deno
        let intX = Int(x)
        guard x == Double(intX) else { return }
    
        
        let y = (arr1[2]*arr2[0] - arr1[0]*arr2[2]) / deno
        let intY = Int(y)
        guard y == Double(intY) else { return }
        
        maxX = max(maxX, intX)
        minX = min(minX, intX)
        maxY = max(maxY, intY)
        minY = min(minY, intY)
        
        if let _ = coordinates[intY] {
            coordinates[intY]?.append(intX)
        } else {
            coordinates.updateValue([intX], forKey: intY)
        }
    }
    
    func combination(_ arr: [[Double]], size: Int, current index: Int, selected: [[Double]]) {
        if size == 0 {
            makeCoordinates(arr1: selected[0], arr2: selected[1])
        } else if index == arr.count {
            return
        } else {
            var newSelected = selected
            newSelected.append(arr[index])
            combination(arr, size: size - 1, current: index + 1, selected: newSelected)
            combination(arr, size: size, current: index + 1, selected: selected)
        }
    }

    combination(line.map { $0.map { Double($0) } }, size: 2, current: 0, selected: [])
    
    var results = [String]()
    for y in (minY...maxY).reversed() {
        var line = [String](repeating: ".", count: maxX - minX + 1)
        if let xArr = coordinates[y] {
            for x in xArr {
                line[x - minX] = "*"
            }
        }
        results.append(line.joined())
    }
    
    return results
}

print(solution([[2, -1, 4], [-2, -1, 4], [0, -1, 1], [5, -8, -12], [5, 8, 12]]))
// ["....*....", ".........", ".........", "*.......*", ".........", ".........", ".........", ".........", "*.......*"]
print(solution([[0, 1, -1], [1, 0, -1], [1, 0, 1]]))  // ["*.*"]
print(solution([[1, -1, 0], [2, -1, 0]]))  // ["*"]
print(solution([[1, -1, 0], [2, -1, 0], [4, -1, 0]]))  // ["*"]

How I tried this :
시간초과를 걱정했지만 다행히 통과되었다.

순열을 이용해서 모든 직선을 2개씩 묶고, 묶인 직선간에 정수 교점을 찾아서 딕셔너리에 넣었다.

딕셔너리로 넣은 이유는 key 값으로 y 좌표에 쉽게 접근해서 x 좌표를 얻으려고 했다.

실제좌표가 저장되기 때문에 minX 값을 빼서 minX가 0좌표가 되도록 만들었다.

 

사실 이 풀이가 안되면.. 큰일 날뻔했다..

더 좋은 풀이가 있을거 같긴하지만... 직관적으로 풀어보았다.

 

문제에 관한 모든 저작권 : https://programmers.co.kr/

728x90