[프로그래머스] 롤 케이크 자르기 Python

김유상·2022년 12월 20일
0

프로그래머스

목록 보기
15/20
post-custom-banner

문제 링크: https://school.programmers.co.kr/learn/courses/30/lessons/132265

문제 내용

철수는 롤케이크를 두 조각으로 잘라서 동생과 한 조각씩 나눠 먹으려고 합니다. 이 롤케이크에는 여러가지 토핑들이 일렬로 올려져 있습니다. 철수와 동생은 롤케이크를 공평하게 나눠먹으려 하는데, 그들은 롤케이크의 크기보다 롤케이크 위에 올려진 토핑들의 종류에 더 관심이 많습니다. 그래서 잘린 조각들의 크기와 올려진 토핑의 개수에 상관없이 각 조각에 동일한 가짓수의 토핑이 올라가면 공평하게 롤케이크가 나누어진 것으로 생각합니다.

예를 들어, 롤케이크에 4가지 종류의 토핑이 올려져 있다고 합시다. 토핑들을 1, 2, 3, 4와 같이 번호로 표시했을 때, 케이크 위에 토핑들이 [1, 2, 1, 3, 1, 4, 1, 2] 순서로 올려져 있습니다. 만약 세 번째 토핑(1)과 네 번째 토핑(3) 사이를 자르면 롤케이크의 토핑은 [1, 2, 1], [3, 1, 4, 1, 2]로 나뉘게 됩니다. 철수가 [1, 2, 1]이 놓인 조각을, 동생이 [3, 1, 4, 1, 2]가 놓인 조각을 먹게 되면 철수는 두 가지 토핑(1, 2)을 맛볼 수 있지만, 동생은 네 가지 토핑(1, 2, 3, 4)을 맛볼 수 있으므로, 이는 공평하게 나누어진 것이 아닙니다. 만약 롤케이크의 네 번째 토핑(3)과 다섯 번째 토핑(1) 사이를 자르면 [1, 2, 1, 3], [1, 4, 1, 2]로 나뉘게 됩니다. 이 경우 철수는 세 가지 토핑(1, 2, 3)을, 동생도 세 가지 토핑(1, 2, 4)을 맛볼 수 있으므로, 이는 공평하게 나누어진 것입니다. 공평하게 롤케이크를 자르는 방법은 여러가지 일 수 있습니다. 위의 롤케이크를 [1, 2, 1, 3, 1], [4, 1, 2]으로 잘라도 공평하게 나뉩니다. 어떤 경우에는 롤케이크를 공평하게 나누지 못할 수도 있습니다.

롤케이크에 올려진 토핑들의 번호를 저장한 정수 배열 topping이 매개변수로 주어질 때, 롤케이크를 공평하게 자르는 방법의 수를 return 하도록 solution 함수를 완성해주세요.

  • 1 ≤ topping의 길이 ≤ 1,000,000
  • 1 ≤ topping의 원소 ≤ 10,000

문제 해설

문제에서 요구하는 것과 같이 토핑 종류의 개수가 같도록 롤 케이크를 자르는 방법을 찾으려면 단순하게 0 번째 원소부터 len(topping)-1까지 한 번씩 잘라보고 거기서 2개로 나눠지는 조각의 토핑의 개수가 같은지 비교하는 방법이 있다. 하지만 이렇게 계산하게 되면 토핑 리스트의 길이를 N이라고 할때, N개의 토핑에 대해 N번 비교해야 하는 O(N^2)의 시간복잡도를 가지게 된다.
토핑의 길이가 최대 1,000,000이기 때문에 제곱의 경우 최대 1,000,000,000,000까지 나올 수 있다. 일반적으로 코딩테스트에서 요구하는 시간 제한이 10초 이내인 것을 보면 1,000,000,000이 넘지 않게 작성해야 한다. 따라서 그 이하로 줄여야만 한다.

필자가 생각한 방법은 set을 이용하는 방법이다. 어차피 종류의 개수를 구하는 문제이기 때문에 각각의 토핑을 일일이 새는 것은 비효율적이기 때문이다. 하지만 단순히 set만을 이용하면 방법이 얼마나 있는지 확인하기 어렵다. 그래서 dict를 이용해서 각각의 topping이 얼마나 있는지 확인하고 keyset을 관리하는 방법을 이용했다.

일단 전체 topping을 r_dict에 <topping, count> 순서로 관리하고 리스트 왼쪽부터 천천히 오른쪽으로 이동하면서 l_dict에 값을 삽입하고 r_dict의 값을 제거해주면 각각의 dict에서 keyset을 온전히 관리할 수 있다. 이렇게 keyset의 개수가 같은 경우 result를 통해 카운팅해주었다.

def solution(topping):
    result = 0
    l_dict = {}
    r_dict = {}
    for top in topping:
        r_dict.setdefault(top, 0)
        r_dict[top] += 1
    for top in topping:
        l_dict.setdefault(top, 0)
        l_dict[top] += 1
        r_dict[top] -= 1
        if r_dict[top] == 0:
            del r_dict[top]
        if len(l_dict.keys()) == len(r_dict.keys()):
            result += 1
    return result
profile
continuous programming
post-custom-banner

0개의 댓글