λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°

πŸ–₯ CS/Algorithm

[Algorithm/Swift] ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€(Lv.3) - 징검닀리 κ±΄λ„ˆκΈ°

μ•ˆλ…•ν•˜μ„Έμš” μ œμΈμž…λ‹ˆλ‹€:) 

PS둜 ν•˜λ£¨λ₯Ό 힘차게 μ‹œμž‘ν•˜λ €κ³  ν–ˆλŠ”λ° 이제 ν•  일을 μ’€ ν•˜κ³  문제λ₯Ό ν’€μ–΄μ•Όκ² μ–΄μš”...γ…‡<-<

였늘 μ €λ₯Ό 괴둭힌 문제λ₯Ό λ³΄μ‹œμ£  징검닀리 κ±΄λ„ˆκΈ° 레쭈고.

문제 링크

 

ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€

μ½”λ“œ μ€‘μ‹¬μ˜ 개발자 μ±„μš©. μŠ€νƒ 기반의 ν¬μ§€μ…˜ 맀칭. ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€μ˜ 개발자 λ§žμΆ€ν˜• ν”„λ‘œν•„μ„ λ“±λ‘ν•˜κ³ , λ‚˜μ™€ 기술 ꢁ합이 잘 λ§žλŠ” 기업듀을 맀칭 λ°›μœΌμ„Έμš”.

programmers.co.kr

문제 풀이

처음 풀이

투 포인터 ν™œμš© (ν…ŒμŠ€νŠΈμΌ€μ΄μŠ€ λͺ¨λ‘ 톡과, but νš¨μœ¨μ„± 0점)

import Foundation

func solution(_ stones:[Int], _ k:Int) -> Int {
    var pointer1 = 0, pointer2 = k-1
    var max = Int.max // 길이 k인 κ΅¬κ°„μ—μ„œμ˜ μ΅œλŒ“κ°’ μ €μž₯

    while pointer2 < stones.count {
        let maxElement = stones[pointer1...pointer2].max()!
        if max > maxElement { max = maxElement }
    
        pointer1 += 1
        pointer2 += 1
    }

    return max
}

 

μ²˜μŒμ—λŠ” 투 포인터λ₯Ό ν™œμš©ν•΄ μŠ¬λΌμ΄λ”© μœˆλ„μš° κΈ°λ²•μœΌλ‘œ k개의 λ””λ”€λŒμ„ ν•œ κ΅¬κ°„μœΌλ‘œ μ„€μ •ν•΄μ„œ 전체λ₯Ό μŠ€μΊ”ν•˜λŠ” λ°©μ‹μœΌλ‘œ ν’€μ—ˆμŠ΅λ‹ˆλ‹€.

μ™œλƒν•˜λ©΄, 징검닀리λ₯Ό 더 이상 κ±΄λ„ˆμ§€ λͺ»ν•˜κ²Œ λ˜λŠ” μˆœκ°„μ€ 적힌 μˆ«μžκ°€ 0이 λ˜λŠ” λ””λ”€λŒμ΄ k개 연달아 λ‚˜μ˜€λŠ” 경우이기 λ•Œλ¬Έμ— 길이가 k인 ꡬ간 μ•ˆμ—μ„œμ˜ μ΅œλŒ“κ°’μ΄ ν•΄λ‹Ή ꡬ간을 건널 수 μžˆλŠ” μ‚¬λžŒμ˜ μ΅œλŒ€ μˆ«μžλΌλŠ” 것을 νŒŒμ•…ν–ˆκ³ , 항상 κ°€μž₯ κ°€κΉŒμš΄ λŒμ„ λ°Ÿμ•„μ•Ό ν•˜λ―€λ‘œ ν•œ μ‚¬λžŒμ΄ 건널 λ•Œλ§ˆλ‹€ 전체 돌의 μˆ«μžκ°€ 1μ”© κ°μ†Œν•˜κΈ° λ•Œλ¬Έμ— 전체 닀리λ₯Ό 건널 수 μžˆλŠ” μ‚¬λžŒμ˜ μ΅œλŒ€ 숫자λ₯Ό κ΅¬ν•˜κΈ° μœ„ν•΄μ„œλŠ” ν•œ κ΅¬κ°„ λ‚΄μ˜ μ΅œλŒ“κ°’μ„ μ €μž₯ν•˜λ©΄μ„œ 더 μž‘μ€ μ΅œλŒ“κ°’μ΄ λ‚˜μ˜€λ©΄ κ°±μ‹ ν•΄μ£ΌλŠ” 방법(μ΅œλŒ“κ°’λ“€ 쀑 μ΅œμ†Ÿκ°’μ΄ μ΅œμ’… λ‹΅)으둜 μ΅œμ’… 값을 ꡬ할 수 μžˆκ² λ‹€κ³  μƒκ°ν–ˆμŠ΅λ‹ˆλ‹€.

 

μ΄λŸ¬ν•œ μ•„μ΄λ””μ–΄λŠ” λ§žμ•˜λ˜ 것 같은데, 전체 닀리λ₯Ό μŠ€μΊ”ν•˜λŠ” κ³Όμ •μ—μ„œ ꡬ간 λ‚΄μ˜ μ΅œλŒ“κ°’μ„ μ°ΎκΈ° μœ„ν•΄ 맀번 전체 배열을 k만큼 μŠ¬λΌμ΄μŠ€ν•΄μ„œ 길이가 k인 μƒˆλ‘œμš΄ 배열을 μƒμ„±ν•˜κ²Œ 되기 λ•Œλ¬Έμ— μ‹œκ°„ λ³΅μž‘λ„κ°€ O(k)κ°€ λ˜μ–΄ 전체 λ°°μ—΄μ˜ 길이가 κΈΈλ‹€λ©΄ λΉ„νš¨μœ¨μ μΈ 탐색 방식이 λ©λ‹ˆλ‹€. (이 문제의 경우 stones λ°°μ—΄μ˜ 크기가 μ΅œλŒ€ 200,000μž…λ‹ˆλ‹€.)

 

νš¨μœ¨μ„±μ„ μ–΄λ–»κ²Œ κ°œμ„ ν• κΉŒ.. ν•˜λ‹€κ°€ 이전에 배열에 μš”μ†Œλ₯Ό 계속 μΆ”κ°€ν•΄μ£Όλ©΄μ„œ μ΅œλŒ“κ°’ or μ΅œμ†Ÿκ°’μ„ μ—…λ°μ΄νŠΈ ν•΄μ£Όμ–΄μ•Ό ν•  λ•Œ μš°μ„ μˆœμœ„ 큐λ₯Ό ν™œμš©ν•œ 기얡이 μžˆμ–΄μ„œ νž™μ„ κ΅¬ν˜„ν•΄μ„œ κ°œμ„ ν•΄λ³΄μž! λΌλŠ” 아이디어가 λ– μ˜¬λžμ§€λ§Œ, μš°μ„ μˆœμœ„ 큐의 크기λ₯Ό 계속 k둜 μœ μ§€ν•˜κΈ° μœ„ν•΄μ„œλŠ” 전체 배열을 μˆœνšŒν•˜λ©° μƒˆλ‘œμš΄ 값을 insert해쀄 λ•Œ λ°°μ—΄μ˜ λ°”λ‘œ 이전 인덱슀의 μš”μ†Œλ₯Ό μš°μ„ μˆœμœ„ νμ—μ„œ μ‚­μ œν•΄μ£Όμ–΄μ•Ό ν•˜λŠ”λ°, μš°μ„ μˆœμœ„ νμ—μ„œλŠ” νŠΉμ • μ›μ†Œλ₯Ό μ°Ύμ•„μ„œ remove 연산을 해쀄 μˆ˜κ°€ μ—†κΈ° λ•Œλ¬Έμ— (μš°μ„ μˆœμœ„ 큐의 μ›μ†ŒλŠ” insert, remove해쀄 λ•Œλ§ˆλ‹€ μˆœμ„œκ°€ λ°”λ€ŒκΈ° λ•Œλ¬Έμ— removeFirst()λ‘œλŠ” 이전 μ‚½μž… κ°’ μ‚­μ œ λΆˆκ°€) 이 λ°©λ²•μœΌλ‘œλŠ” κ°œμ„ ν•  수 μ—†κ² κ΅¬λ‚˜..λ₯Ό κΉ¨λ‹«κ³  λ‹€λ₯Έ 풀이λ₯Ό μ°Ύμ•„λ³΄μ•˜μŠ΅λ‹ˆλ‹€.. 

μ΅œμ’… 풀이

λ‹€λ₯Έ λΈ”λ‘œκ·Έλ“€μ˜ 풀이λ₯Ό μ°Έκ³ ν•œ κ²°κ³Ό, 이뢄 탐색 μ•Œκ³ λ¦¬μ¦˜μ„ μ‚¬μš©ν•΄μ„œ 문제λ₯Ό ν•΄κ²°ν•  수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€. (이뢄 탐색은 생각지도 λͺ»ν–ˆμ–΄μš”)

건널 수 μžˆλŠ” μ‚¬λžŒμ˜ 수λ₯Ό 반으둜 μ€„μ—¬κ°€λ©΄μ„œ ν™•μΈν•˜λŠ” λ°©μ‹μœΌλ‘œ 졜적의 ν•΄λ₯Ό μ°Ύμ•„λ‚΄λŠ” λ°©μ‹μ΄μ—ˆλŠ”λ°μš”, 이뢄 탐색을 μ΄μš©ν•œ 풀이 과정은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

1. left와 rightλ₯Ό 각각 stones λ°°μ—΄μ˜ μ›μ†Œκ°€ 될 수 μžˆλŠ” μ΅œμ†Ÿκ°’κ³Ό μ΅œλŒ€κ°’μœΌλ‘œ μ΄ˆκΈ°ν™”ν•©λ‹ˆλ‹€. (left = 1, right = 200000000)
2. midλͺ…μ˜ μ‚¬λžŒμ΄ 징검닀리λ₯Ό 건널 수 μžˆλŠ”μ§€ ν™•μΈν•΄λ΄…λ‹ˆλ‹€.
3-1. 2의 κ³Όμ •μ—μ„œ 건널 수 있으면 midλͺ… μ΄μƒμ˜ λ²”μœ„λ₯Ό νƒμƒ‰ν•˜λ©΄ λ˜λ―€λ‘œ left 값을 mid+1둜 λ°”κΏ‰λ‹ˆλ‹€.
3-2. 2의 κ³Όμ •μ—μ„œ 건널 수 μ—†λ‹€λ©΄ right 값을 midλͺ… μ΄ν•˜μ˜ λ²”μœ„λ₯Ό νƒμƒ‰ν•˜λ©΄ λ˜λ―€λ‘œ mid둜 λ°”κΏ‰λ‹ˆλ‹€.
4. 건널 수 μžˆλŠ” μ΅œλŒ€ λͺ…μˆ˜λ₯Ό ꡬ해야 ν•˜λ―€λ‘œ, left < right 인 λ™μ•ˆ μœ„μ˜ 과정을 λ°˜λ³΅ν•©λ‹ˆλ‹€. 

Swift 풀이 μ½”λ“œ

import Foundation

func solution(_ stones:[Int], _ k:Int) -> Int {
    var left = 1
    var right = 200000000
    
    while left < right {
        let mid = (left + right) / 2
        var skipCount = 0 // κ±΄λ„ˆλ›°μ–΄μ•Όν•˜λŠ” 돌의 개수
        
        for i in 0..<stones.count {
            if stones[i] - mid <= 0 { // 점수 0 μ΄ν•˜λ‘œ λ–¨μ–΄μ§€λŠ” κ³³ 생기면
                skipCount += 1
                
                if skipCount >= k { // 점수 0λ˜λŠ” 곳이 연달아 k개 이상 λ‚˜μ˜€λ©΄
                    break // 반볡문 νƒˆμΆœ
                }
            } else { // midλͺ…λ§ŒνΌ 건널 수 있으면
                skipCount = 0 // skipCount μ΄ˆκΈ°ν™”
            }
        }
        
        // κ°€λŠ₯ 여뢀에 따라 left, right λ‹€μ‹œ μ„€μ •
        if skipCount >= k { // midλͺ… 건널 수 μ—†μœΌλ©΄ midλͺ… μ΄ν•˜μ˜ λ²”μœ„λ₯Ό 탐색
            right = mid
        } else { // midλͺ… κ±΄λ„μˆ˜ 있으면 midλͺ… μ΄μƒμ˜ λ²”μœ„λ₯Ό 탐색
            left = mid + 1
        }
    }
 
    return left
}

 


[참고 자료]

 

[Swift μ•Œκ³ λ¦¬μ¦˜] ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€(Lv.3) - 징검닀리 κ±΄λ„ˆκΈ° / 2019 카카였 인턴십

μ•ˆλ…•ν•˜μ„Έμš”. 개발 쀑인 μ •μ£Όμž…λ‹ˆλ‹€. μ˜€λŠ˜μ€ "ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€(Lv.3) - 징검닀리 κ±΄λ„ˆκΈ°" 문제λ₯Ό ν’€μ—ˆμŠ΅λ‹ˆλ‹€. Github GitHub - jeongju9216/SwiftAlgorithm: μŠ€μœ„ν”„νŠΈ μ•Œκ³ λ¦¬μ¦˜ μŠ€μœ„ν”„νŠΈ μ•Œκ³ λ¦¬μ¦˜. Contribute to jeongju9

jeong9216.tistory.com

 

ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€: 징검닀리 κ±΄λ„ˆκΈ° - Swift

https://school.programmers.co.kr/learn/courses/30/lessons/64062징검닀리λ₯Ό κ±΄λ„μˆ˜ μžˆλŠ” μΉœκ΅¬λ“€μ˜ 수둜 이뢄탐색을 μˆ˜ν–‰ν•˜λ©΄ κ°„λ‹¨νžˆ ν’€ 수 μžˆλ‹€

velog.io

 

[μ•Œκ³ λ¦¬μ¦˜ 문제 풀이] ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€ 징검닀리 κ±΄λ„ˆκΈ°

ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€ 징검닀리 κ±΄λ„ˆκΈ° 풀이

facerain.club