[프로그래머스/Lv2] 할인 행사

2022. 11. 29. 13:38

https://school.programmers.co.kr/learn/courses/30/lessons/131127

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 

코드

from collections import deque

def solution(want, number, discount):
    want_dict = {}
    for goods, n in zip(want, number):
        want_dict[goods] = n

    deq_discount = deque(discount)
    answer = 0
    check = True
    while check:
        try:
            discount_dict = {}
            for i in range(10):
                try:
                    discount_dict[deq_discount[i]] += 1
                except:
                    discount_dict[deq_discount[i]] = 1
            
            discount_check = 0
            for key, value in want_dict.items():
                try:
                    if discount_dict[key] >= value:
                        discount_check += 1
                except:
                    pass
            
            if discount_check == len(want_dict):
                answer += 1
            
            deq_discount.popleft()
        except:
            check = False
    
    return answer

 

 

설명

처음 문제를 보면 글자가 굉장히 많아서 겁먹을 수도 있는데

다른 2레벨 문제들에 비하면 굉장히 쉬운 편인것 같다.

 

문제에 대한 상세 설명도 필요 없이 차근차근 한 번 읽어보면 이해가 잘 된다.

 

문제는 아래와 같은 방법으로 풀어볼 것이다.

우선 구매하고 싶은 물건들의 이름과 개수를 기록하는 딕셔너리를 만든다.

그 후 할인품목 리스트(discount)의 첫 원소부터 10개까지 물건들의 각 개수를 세어 마찬가지로 딕셔너리로 만든다.

 

첫번째 딕셔너리의 물건들을 키로 두번째 딕셔너리를 검색한다.

그렇게 나온 값은 회원가입한 날부터 열흘동안 해당 물건에 대한 할인 횟수를 나타낼 것이다.

그 값이 첫번째 딕셔너리의 물건에 해당하는 값과 같거나 크다면 일단 그 품목은 조건에 맞다고 체크해둔다.

 

이렇게 체크한 개수가 첫번째 딕셔너리의 길이와 같다면 이 날짜에 회원등록하면 모든 물건을 할인해서 살 수 있다는 뜻이 된다.

 

위 과정을 discount 리스트의 가장 왼쪽 원소를 pop하면서 반복하는데, 길이가 10보다 작으면 반복을 멈춘다.

 

 

want_dict = {}
for goods, n in zip(want, number):
    want_dict[goods] = n

want_dict는 원하는 물건들과 그 개수를 키와 값으로 하는 딕셔너리이다.

주어진 want와 number 리스트로 want_dict를 초기화한다.

 

from collections import deque

deq_discount = deque(discount)

discount를 deque로 변환해 deq_discount에 저장한다.

pop(0)는 O(n)의 시간복잡도를 가지는 반면

deque의 popleft()는 O(1)의 시간복잡도를 가지기 때문에

단순 리스트로 구현하기보다 deque로 구현했다.

 

answer = 0
check = True
while check:

answer는 정답을 기록하는 변수이다.

check가 True일 때 아래 while문이 동작한다.

 

try:
    discount_dict = {}
    for i in range(10):
        try:
            discount_dict[deq_discount[i]] += 1
        except:
            discount_dict[deq_discount[i]] = 1

    discount_check = 0
    for key, value in want_dict.items():
        try:
            if discount_dict[key] >= value:
                discount_check += 1
        except:
            pass

    if discount_check == len(want_dict):
        answer += 1

    deq_discount.popleft()
except:
    check = False

while문의 내부 동작이다.

이 코드에서 쪼개가면서 다시 설명한다.

 

discount_dict = {}
for i in range(10):
    try:
        discount_dict[deq_discount[i]] += 1
    except:
        discount_dict[deq_discount[i]] = 1

discount_dict는 할인 품목과 그 개수를 딕셔너리로 표현한 변수이다.

0부터 9까지(10개) 반복한다.

discount_dict에 deq_discount[i](물건 이름)이 이미 키로 존재한다면 그 키에 해당하는 값에 1을 더한다.

그렇지 않다면 deq_discount[i]을 키로 가지는 값을 1로 초기화한다.

 

discount_check = 0
for key, value in want_dict.items():
    try:
        if discount_dict[key] >= value:
            discount_check += 1
    except:
        pass

discount_check는 원하는 물건의 할인 여부를 기록하는 변수이다.

want_dict의 키와 값을 꺼내며 반복한다.

만약 discount_dict에 key에 해당하는 키가 존재한다면 그 키에 해당하는 값과 value를 비교하여

value보다 크거나 같다면 discount_check에 1을 더한다.

그렇지 않다면 아무 작업없이 넘어간다.

 

if discount_check == len(want_dict):
    answer += 1

구해놓은 discount_check와 want_dict의 길이를 비교하여 같다면 answer에 1을 더한다.

 

deq_discount.popleft()

deq_discount의 가장 왼쪽 원소를 pop한다.

 

여기까지가 가장 바깥쪽 try문의 작업 내용이다.

 

check = False

except문의 동작은 check를 False로 변경하여 while문을 종료하도록한다.

여기서 가장 바깥쪽의 try, except문의 분기를 담당하는 에러는 IndexError로

deq_discount의 길이가 10보다 작게 되면 IndexError가 발생하여 while문이 종료된다.

 

return answer

구해놓은 answer를 반환한다.

BELATED ARTICLES

more