[Swift - ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€] μžλ¬Όμ‡ μ™€ μ—΄μ‡ 

2021. 6. 3. 18:45γ†πŸ§‘πŸ»‍πŸ’» iOS 개발/Swift - Algorithm - Solutions

πŸ•΅πŸ»  λ¬Έμ œ 해석 


κ³ κ³ ν•™μžμΈ  "튜브"λŠ” κ³ λŒ€ μœ μ μ§€μ—μ„œ 보물과 유적이 가득할 κ²ƒμœΌλ‘œ μΆ”μ •λ˜λŠ” λΉ„λ°€μ˜ 문을 λ°œκ²¬ν•˜μ˜€μŠ΅λ‹ˆλ‹€. μž κ²¨μžˆλŠ” μžλ¬Όμ‡ λŠ” 격자 ν•œ 칸의 크기가  1 x 1인  N x N ν¬κΈ°μ˜ 정사각 격자 ν˜•νƒœμ΄κ³  νŠΉμ΄ν•œ λͺ¨μ–‘μ˜ μ—΄μ‡ λŠ” M x M ν¬κΈ°μΈ 정사각 격자 ν˜•νƒœλ‘œ λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

μžλ¬Όμ‡ μ—λŠ” ν™ˆμ΄ νŒŒμ—¬ 있고 μ—΄μ‡  λ˜ν•œ ν™ˆκ³Ό 돌기 뢀뢄이 μžˆμŠ΅λ‹ˆλ‹€. μ—΄μ‡ λŠ” νšŒμ „κ³Ό 이동이 κ°€λŠ₯ν•˜λ©° μ—΄μ‡ μ˜ 돌기 뢀뢄을 μžλ¬Όμ‡ μ˜ ν™ˆ 뢀뢄에 λ”± 맞게 μ±„μš°λ©΄ μžλ¬Όμ‡ κ°€ μ—΄λ¦¬κ²Œ λ˜λŠ” κ΅¬μ‘°μž…λ‹ˆλ‹€. μžλ¬Όμ‡  μ˜μ—­μ„ λ²—μ–΄λ‚œ 뢀뢄에 μžˆλŠ” μ—΄μ‡ μ˜ ν™ˆκ³Ό λŒκΈ°λŠ” μžλ¬Όμ‡ λ₯Ό μ—¬λŠ” 데 영ν–₯을 주지 μ•Šμ§€λ§Œ, μžλ¬Όμ‡  μ˜μ—­ λ‚΄μ—μ„œλŠ” μ—΄μ‡ μ˜ 돌기 λΆ€λΆ„κ³Ό μžλ¬Όμ‡ μ˜ ν™ˆ 뢀뢄이 μ •ν™•νžˆ μΌμΉ˜ν•΄μ•Ό ν•˜λ©° μ—΄μ‡ μ˜ λŒκΈ°μ™€ μžλ¬Όμ‡ μ˜ λŒκΈ°κ°€ λ§Œλ‚˜μ„œλŠ” μ•ˆλ©λ‹ˆλ‹€. λ˜ν•œ μžλ¬Όμ‡ μ˜ λͺ¨λ“  ν™ˆμ„ μ±„μ›Œ λΉ„μ–΄μžˆλŠ” 곳이 μ—†μ–΄μ•Ό μžλ¬Όμ‡ λ₯Ό μ—΄ 수 μžˆμŠ΅λ‹ˆλ‹€.

  • keyλŠ” M x M(3 ≤ M ≤ 20, M은 μžμ—°μˆ˜) 크기 2차원 λ°°μ—΄μž…λ‹ˆλ‹€.
  • lock은 N x N(3 ≤ N ≤ 20, N은 μžμ—°μˆ˜)크기 2차원 λ°°μ—΄μž…λ‹ˆλ‹€.
  • M은 항상 N μ΄ν•˜μž…λ‹ˆλ‹€.
  • key와 lock의 μ›μ†ŒλŠ” 0 λ˜λŠ” 1둜 이루어져 μžˆμŠ΅λ‹ˆλ‹€.
  • 0은 ν™ˆ λΆ€λΆ„, 1은 돌기 뢀뢄을 λ‚˜νƒ€λƒ…λ‹ˆλ‹€.

πŸ€” 풀이 κ³Όμ •


λ¨Όμ €, 문제λ₯Ό 보고 정사각 ν–‰λ ¬ ν˜•νƒœλ‘œ 주어진 μ—΄μ‡ λ₯Ό μ‹œκ³„ λ°©ν–₯으둜 90도 νšŒμ „μ‹œν‚€λŠ” ν•¨μˆ˜κ°€ 제일 λ¨Όμ € ν•„μš”ν•˜κ² κ΅¬λ‚˜ μ‹Άμ—ˆμŠ΅λ‹ˆλ‹€.  

func rotateKey90DegreesClockwise(_ key: [[Int]]) -> [[Int]] {
     var rotatedKey = [[Int]](repeating: [Int](repeating: 0, count: M), count: M)
     
     for col in 0..<M {
         for row in (0..<M).reversed() {
              rotatedKey[col][M - 1 - row] = key[row][col]
         }
     }
        
     return rotatedKey
}

μ €λŠ” λ‹€μŒκ³Ό 같이 μž‘μ„±ν–ˆλŠ”λ°, 행에 있던 데이터듀이 νšŒμ „λœ ν–‰λ ¬μ—μ„œλŠ” μ—΄ 데이터가 λ˜λ―€λ‘œ 3 X 3 μ •λ„μ˜ μ˜ˆμ‹œ 행렬을 λ³΄λ©΄μ„œ κ·Έμ— λ§žμΆ”μ–΄ λ°˜λ³΅λ¬Έμ„  μž‘μ„±ν•΄λ³΄μ•˜μŠ΅λ‹ˆλ‹€. ꡬ글에 ν–‰λ ¬ νšŒμ „μ— λŒ€ν•œ μ„€λͺ…이 μžμ„Έν•˜κ²Œ λ‚˜μ™€μžˆμœΌλ―€λ‘œ 이 뢀뢄은 κ±΄λ„ˆλ›°μ–΄λ„ 되겠죠? πŸ₯Ί

자 이제, μ—΄μ‡ λ₯Ό νšŒμ „ μ‹œν‚¬ 수 μžˆμœΌλ‹ˆ μžλ¬Όμ‡ μ— λ§žμΆ”μ–΄ λ³΄μ•„μ•Όκ² μŠ΅λ‹ˆλ‹€. νšŒμ „μ‹œν‚¨ μ—΄μ‡  행렬을 κ°€λŠ₯ν•œ λͺ¨λ“  μœ„μΉ˜λ§ˆλ‹€ μžλ¬Όμ‡  ν–‰λ ¬κ³Ό 더 ν•΄μ£Όμ—ˆμ„ λ•Œ μžλ¬Όμ‡  ν–‰λ ¬μ˜ 값듀이 λͺ¨λ‘ 1이 되면 μžλ¬Όμ‡ κ°€ μ—΄λ¦°λ‹€κ³  νŒλ‹¨ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 

λ§Œμ•½ μžλ¬Όμ‡  ν–‰λ ¬μ˜ 값쀑에 0이 μ‘΄μž¬ν•œλ‹€λ©΄, μ±„μ›Œμ§€μ§€ μ•Šμ€ ν™ˆμ΄ μžˆλ‹€λŠ” 것이고 2κ°€ μ‘΄μž¬ν•œλ‹€λ©΄ μžλ¬Όμ‡ μ˜ λŒκΈ°μ™€ μ—΄μ‡ μ˜ λŒκΈ°κ°€ λ§Œλ‚¬λ‹€κ³  νŒλ‹¨ν•˜κ³  이 κ²½μš°μ—λŠ” false 처리λ₯Ό ν•΄μ£Όμ—ˆμŠ΅λ‹ˆλ‹€. 

μ„€λͺ…을 돕기 μœ„ν•΄ λ¬Έμ œμ—μ„œ μ˜ˆμ‹œλ‘œ μ€€ 3 X 3 μžλ¬Όμ‡ μ™€ μ—΄μ‡ λ₯Ό λ°”νƒ•μœΌλ‘œ ν–‰λ ¬ ν‘œλ₯Ό μž‘μ„±ν•΄λ΄€μŠ΅λ‹ˆλ‹€.πŸ˜… 이 ν‘œλŠ” ν™•μž₯된 μžλ¬Όμ‡  μ˜μ—­μ„ ν‘œν˜„ν•œ κ²ƒμΈλ°μš”, λ¬Έμ œμ—μ„œ μ—΄μ‡ μ˜ 크기인 N은 항상 Mμ΄ν•˜λΌκ³  ν–ˆκΈ° λ•Œλ¬Έμ— μ–΄λŠ λ°©ν–₯으둜 μ—΄μ‡ λ₯Ό 겹치던 3 * N X 3 * N ν–‰λ ¬ μ•ˆμ—μ„œ κ²Ήμ³μ§€κ²Œ λœλ‹€κ³  νŒλ‹¨ν•΄μ„œ μ΄λ ‡κ²Œ ν•΄μ£Όμ—ˆμŠ΅λ‹ˆλ‹€. λ…Έλž€μƒ‰μ˜ 셀은 ν–‰λ ¬μ˜ μΈλ±μŠ€μž…λ‹ˆλ‹€!

μ›λž˜ μžλ¬Όμ‡  행렬은 ν™•μž₯된 ν–‰λ ¬ μ•ˆμ—μ„œ [N..<2 * N][N..<2 * N]에 μœ„μΉ˜ν•˜κ³  μžλ¬Όμ‡  ν–‰λ ¬μ˜μ—­κ³Ό μ—΄μ‡  ν–‰λ ¬ μ˜μ—­μ΄ ν•˜λ‚˜ 이상은 겹쳐야 ν•˜κΈ° λ•Œλ¬Έμ— (κ²ΉμΉ˜μ§€ μ•ŠμœΌλ©΄ μžλ¬Όμ‡ μ— μ—΄μ‡ λ₯Ό μ•ˆ λΌμš°λŠ” 격이 λ©λ‹ˆλ‹€..) μ—΄μ‡  행렬이 μœ„μΉ˜ν•  수 μžˆλŠ” μ˜μ—­μ€ λΉ¨κ°„μƒ‰μœΌλ‘œ ν…Œλ‘λ¦¬ 쳐둔 뢀뢄이 λ©λ‹ˆλ‹€.

보톡 이쀑 for문으둜 행렬을 탐색할 λ•Œ μ’Œμƒλ‹¨λΆ€ν„° 탐색을 ν•˜κΈ° λ•Œλ¬Έμ— 빨간색 μ˜μ—­μ„ μ—΄μ‡  행렬인 M X Mκ³Ό 맀칭 μ‹œμΌœ νƒμƒ‰ν•˜λ €λ©΄ κ·Έ 탐색을 μ‹œμž‘ν•˜λŠ” μ’Œν‘œκ°€ [N - M + 1 ..< 2 * N] [N - M + 1 ..< 2 * N] μ— μœ„μΉ˜ν•˜κ²Œ λ©λ‹ˆλ‹€. 

이λ₯Ό ν‘œλ‘œ ν‘œν˜„ν•˜λ©΄ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

μ΄λ ‡κ²Œ 탐색 지점을 νŒŒμ•…ν•˜κ³  λ‚˜μ„œ μž…λ ₯받은 μ—΄μ‡  행렬을 νšŒμ „μ‹œν‚€λ©° ν•΄λ‹Ή μ˜μ—­μ„ 탐색해보고 μžλ¬Όμ‡ κ°€ μ—΄λ¦¬λŠ” μΌ€μ΄μŠ€λ₯Ό νŒλ‹¨ν•΄μ£Όλ©΄ 될 것 κ°™μŠ΅λ‹ˆλ‹€.  ν‘œλ‘œ λ§Œλ“€κΈ΄ ν–ˆλŠ”λ°.. 이해에 도움이 λ˜μ—ˆμœΌλ©΄ ν•©λ‹ˆλ‹€.πŸ˜‚ ν˜Ήμ‹œλ‚˜ 문제 μ„€λͺ…에 였λ₯˜κ°€ 있으면 λŒ“κΈ€λ‘œ μ•Œλ €μ£Όμ„Έμš”!

πŸ“¦  λ¬Έμ œ 풀이 & μ½”λ“œ


import Foundation

func solution(_ key:[[Int]], _ lock:[[Int]]) -> Bool {
    let M = key.count
    let N = lock.count
    
    // 3 * N X 3 * N 으둜 ν™•μž₯μ‹œν‚¨ μžλ¬Όμ‡  ν–‰λ ¬
    var extendedLock = [[Int]](repeating: [Int](repeating: 0, count: 3 * N), count: 3 * N)
    
    // ν™•μž₯된 ν–‰λ ¬μ—μ„œ μ›λž˜μ˜ μžλ¬Όμ‡ ν–‰λ ¬μ΄ μœ„μΉ˜ν•˜λŠ” λ²”μœ„
    let extendedRange = N..<2 * N

    // 90도 μ‹œκ³„λ°©ν–₯ νšŒμ „
    func rotateKey90DegreesClockwise(_ key: [[Int]]) -> [[Int]] {
        var rotatedKey = [[Int]](repeating: [Int](repeating: 0, count: M), count: M)
        for col in 0..<M {
            for row in (0..<M).reversed() {
                rotatedKey[col][M - 1 - row] = key[row][col]
            }
        }
        return rotatedKey
    }
    
    // ν™•μž₯된 ν–‰λ ¬μ—μ„œ μžλ¬Όμ‡ μœ„μΉ˜λ₯Ό νƒμƒ‰ν•˜λ©° μ—΄λ¦¬λŠ”μ§€ νŒλ‹¨
    func canOpen(_ lock: [[Int]]) -> Bool {
        for i in extendedRange {
            for j in extendedRange {
                // 0 이 μ‘΄μž¬ν•˜λ©΄ μ±„μ›Œμ§€μ§€ μ•Šμ€ ν™ˆ, 2이면 돌기끼리 λ§Œλ‚œ 경우 false 리턴
                if lock[i][j] != 1 {
                    return false
                }
            }
        }
        return true
    }
    
    // μž…λ ₯λ°›μ•˜μ„ λ•Œ, μžλ¬Όμ‡ κ°€ λͺ¨λ‘ 1인 경우 μ—΄λ €μžˆμœΌλ―€λ‘œ true 리턴
    if (lock.filter{$0.contains(0)}).isEmpty {
        return true
    }
    
    // ν™•μž₯
    for i in 0..<N {
        for j in 0..<N {
            extendedLock[i + N][j + N] = lock[i][j]
        }
    }
    
    var tempKey = key
    var tempExtendedLock = extendedLock
    
    for _ in 0..<4 {
        for i in (N - M + 1)..<2 * N {
            for j in (N - M + 1)..<2 * N  {
                tempExtendedLock = extendedLock
                for row in 0..<M {
                    for col in 0..<M {
                        tempExtendedLock[i + row][j + col] += tempKey[row][col]
                    }
                }
                
                if canOpen(tempExtendedLock) {
                    return true
                }
            }
        }
        // ν‚€λ₯Ό νšŒμ „μ‹œν‚€λ©΄μ„œ μ—΄λ¦¬λŠ”μ§€ 체크
        tempKey = rotateKey90DegreesClockwise(tempKey)
    }
    return false
}

🀷🏻‍♂️ 더 생각해보기


제 κ²½μš°λŠ” canOpenμ΄λΌλŠ” ν•¨μˆ˜λ₯Ό λ”°λ‘œ μž‘μ„±ν•˜μ—¬ 이쀑 for 문을 톡해 일일이 μžλ¬Όμ‡ μ˜μ—­μ„ ν™•μΈν•΄μ£Όμ—ˆμ§€λ§Œ, 호좜 전에 값을 λ”ν•˜λŠ” κ³Όμ •μ—μ„œ 1이 μ•„λ‹Œ 값이 λ‚˜μ˜€λ©΄ λ°”λ‘œ λ°˜λ³΅λ¬Έμ„ breakν•˜λŠ” 처리λ₯Ό ν•˜λ©΄ μ’€ 더 효율적인 풀이가 될 λ“― μ‹ΆμŠ΅λ‹ˆλ‹€. 저도 μ’€ 더 λΉ λ₯΄κ²Œ ν’€ μˆ˜μžˆλŠ” 방법을 κ³΅λΆ€ν•΄μ•Όκ² λ„€μš”.πŸ₯²

 

μ½”λ”©ν…ŒμŠ€νŠΈ μ—°μŠ΅ - μžλ¬Όμ‡ μ™€ μ—΄μ‡ 

[[0, 0, 0], [1, 0, 0], [0, 1, 1]] [[1, 1, 1], [1, 1, 0], [1, 0, 1]] true

programmers.co.kr