코딩테스트

[Swift 알고리즘] Codility - MaxCounters

유정주 2022. 6. 18. 12:28
반응형

안녕하세요. 개발 중인 정주입니다.

 

오늘은 "Codility - MaxCounters" 문제를 풀었습니다.

 

Github

 

GitHub - jeongju9216/SwiftAlgorithm: 스위프트 알고리즘

스위프트 알고리즘. Contribute to jeongju9216/SwiftAlgorithm development by creating an account on GitHub.

github.com

 

문제 링크

 

MaxCounters coding task - Learn to Code - Codility

Calculate the values of counters after applying all alternating operations: increase counter by 1; set value of all counters to current maximum.

app.codility.com

 

풀이

이번 문제는 O(N) 알고리즘으로 아래 두 개의 연산을 해야 하는 문제입니다.

  • increase : 1 <= A[i] <= N 이라면 arr[i] += 1 을 합니다.
  • maxCounter : A[i] > N 이라면 모든 원소에 arr.max( )를 대입합니다.

여기에서 해답 포인트는 maxCounter입니다.

maxCounter를 매 반복마다 해준다면 O(N^2) 혹은 O(N+M)이 됩니다.

저도 처음에는 O(N^2)으로, 두 번째는 O(N+M)이 되었는데요.

 

이것을 O(N)으로 해결하려면 마지막에 한 번만 처리를 해줘야 합니다.

즉, 매번 그때그때 처리하는 것이 아니라 후처리를 해야 한다는 의미입니다.

 

따라서 increase 연산을 할 때 최대값을 저장하고 maxCounter 연산을 해야할때 그 값을 저장해둡니다.

만약 increase 연산 시에 해당 원소 값이 마지막 maxCounter보다 작다면 그 값을 maxCounter값으로 대입하고 +1 을 합니다.

모든 counter 연산을 끝내고 마지막에 maxCounter보다 작은 값을 maxCounter로 바꿉니다.

 

이렇게 O(N)으로 해결할 수 있었습니다.

 

알게된 것

지금까지 부담 없이 사용했던 max( )는 O(N)이었습니다.

지금까지 왜 이렇게 편하게만 생각했는지 이해가 안 될 정도네요.

만약 이 문제에서 max( )로 최대값을 구한다면 O(N^2)이 되는 것입니다.

그래서 아래 코드에서 보듯이 increase 연산을 할 때 max 값을 구해줬습니다.

이런 사소한 곳에서도 많은 최적화가 가능하구나... 라는 것을 알게 되었습니다.

 

추가로 Array(repeating:, count:)는 O(배열 길이)이라는 것! ㅎㅎ..

아래 코드의 주석처리한 부분은 이 부분을 생각하지 못해 O(N+M)으로 실패한 것입니다.

 

코딜리티... 시작하길 아주 잘한 것 같아요!

 

전체 코드

더보기
import Foundation

public func solution(_ N : Int, _ A : inout [Int]) -> [Int] {
    var array: [Int] = Array(repeating: 0, count: N)
    var maxValue = 0, maxCounter = 0
    for counter in A {
        if counter == N+1 {
            maxCounter = maxValue //맨 뒤에 후처리 한다
        } else {
            if array[counter-1] < maxCounter {
                array[counter-1] = maxCounter
            }
            array[counter-1] += 1
            maxValue = max(maxValue, array[counter-1]) //array.max()는 O(N)
        }
    }

    for (i, num) in array.enumerated() {
        if num < maxCounter {
            array[i] = maxCounter
        }
    }

    return array
}

//O(N+M)
//public func solution(_ N : Int, _ A : inout [Int]) -> [Int] {
//    var array: [Int] = Array(repeating: 0, count: N)
//    var maxValue = 0
//    for counter in A {
//        if counter == N+1 {
//            array = Array(repeating: maxValue, count: N)
//        } else {
//            array[counter-1] += 1
//            maxValue = max(maxValue, array[counter-1]) //array.max()는 O(N)
//        }
//    }
//
//    return array
//}

아직은 초보 개발자입니다.

더 효율적인 코드 훈수 환영합니다!

공감 댓글 부탁드립니다.

 

 

반응형