jh.nrtv

[코테 문제풀이]Programmers-2023 KAKAO BLIND RECRUITMENT- 개인정보 수집 유효기간, 이모티콘 할인행사, 택배 배달과 수거하기 / Python 풀이 본문

코테 문제풀이

[코테 문제풀이]Programmers-2023 KAKAO BLIND RECRUITMENT- 개인정보 수집 유효기간, 이모티콘 할인행사, 택배 배달과 수거하기 / Python 풀이

wlgus3 2023. 10. 29. 01:07

프로그래머스에서 '2023 KAKAO BLIND RECRUITMENT ' 기출문제를 풀고 기록한 글이다.

허접한 풀이지만 누군가에게 도움이 되길 바라며!

✅ 개인정보 수집 유효기간 

 

프로그래머스

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

programmers.co.kr

문제설명

>>> input

today현재날짜를 제시하고 

terms로 각 약관종류보관 유효기간을 제시하고 

privacies로 수집한 개인정보의 수집일과 약관 종류를 제시한 후에 

>>> ouput

현 날짜기준 파기해야 할 개인정보의 번호를 return해야한다.

 

풀이

단순 구현 문제로 느꼈다.

다만 위와 같이 파라미터를 '.'과 ' '가 섞인 형태로 주기 때문에 필요한 정보를 얻기 위해서 파라미터를 가공해서 써야 하는 점이 번거로웠다.

 

나는 날짜비교시 number 형태로 만들어서 풀었으며 

날짜비교시 숫자 형태로 크기 비교를 하고 더 큰 숫자가 더 미래의 시점이라고 판단했다.

그 외에는 까다로운 점이 없었고 문제 이해 및 정리에 시간이 오래 걸렸다.

 

정답코드

function solution(today, terms, privacies) {
    var answer = [];
    //모든 달은 28일까지 있다.
    //today "YYYY.MM.DD" 형태로 오늘 날짜
    //terms 1<=. <=20인 Array  "A 6"형태로 유효기간 유효기간은 1~100
    //privacies 1<=  <=100인 Array  "2021.05.02 A" 형태
    const todayarr=today.split('.')
    let todayNumber=Number(todayarr[0])*10000+Number(todayarr[1])*100+Number(todayarr[2])//숫자로 비교할 것이기 때문에 현 날짜를 8자리 수로 변환
    termsobj={}
    for (i of terms){
        let [name,month]=i.split(' ')   //구조분해할당
        termsobj[name]=Number(month)
    }
    
    let index=1 //개인정보의 번호 -> 순회하면서 번호 +1해서 맞춰줄 예정 
    for (p of privacies){   //차례로 순회하면서 각 개인정보의 데드라인 계산후 오늘의 날짜와 비교
        [start,name]=p.split(' ')
        let expmonth=termsobj[name]
        let [year,month,day]=start.split('.')
        day=Number(day)-1
        year= Number(year)+Math.floor(expmonth/12)
        month=Number(month)+(expmonth%12)
        if (day==0){
            month=month-1
            day=28}
        if (month >12){
            month-=12
            year+=1
        }
        //삭제할 경우를 찾자 -> 현날짜>데드라인
        let deadline=year*10000+month*100+day   //데드라인 숫자로 변환
        if (deadline<todayNumber){
            answer.push(index)
        }
        index+=1    //개인정보 번호 전진 

    }
    return answer;
}

 


 이모티콘 할인행사 

 

프로그래머스

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

programmers.co.kr

소요시간 : 35m

문제설명

>>> input

users의 구매기준 할인율과, 이모티콘 플러스를 구매할 기준금액을 제시하고 

emoticons들의 가격을 제시한다.

>>> ouput

[이모티콘 플러스 가입자, 총 구매금액] 을 반환

풀이

이 문제 또한 지문이 길어서 이해하기가 까다로웠다.

문제풀이의 핵심은 각 '이모티콘마다 할인율은 다를 수 있으며, 할인율은 10%, 20%, 30%, 40% 중 하나로 설정됩니다.'라는 조건을 읽고 중복순열 을 떠올릴 수 있어야 한다. 

 

할인율의 종류가 4가지 뿐이고, 유저의 수도 최 100명, 이모티콘의 종류는 최대 7가지이다. 따라서 중복순열을 구한 후에 해당 중복순열을 모두 순회해도 시간복잡도에 걸릴 가능성은 낮다.

 

따라서 각 이모티콘의 할인율을 [ 0.1, 0.2, 0.3, 0.4] 중에 하나를 고를 수 있는 중복순열의 모든 종류를 구한 후에 모든 경우의 수를 discout 라는 list에 담고, 해당 list를 순회하면서 이모티콘 플러스를 가입한 숫자가 가장 많으면서, 구매금액도 가장 큰 경우를 업데이트 한다. 

 

여기서 주의할 점은 '이모티콘 플러스 가입자 수 ' 기준이 '이모티콘 구매 총액'기준보다 우선하기 때문에 유념하고 조건식을 짜주어야 한다.

 

 

정답코드

# 1044~ 1117
from itertools import product
def solution(users, emoticons):
    # 가입자 최대 늘리기 - 판매액 최대로 늘리기 
    # 개인 기준할인율 이상 할인 모두구매, 총액기준 넘으면 플러스서비스 구매
    #이모티콘마다 할인율 다를수있꼬 10 20 30 40중 하나로 설정
    #   1<= users <=100 , [[할인율, 가격],[] ...] 형태 
    #   1<=emoticons<=7 , [가격, 가격2, 가격3] 형태 

    #중복순열으로 할인율4가지 * emoticons종류 를 구한다. ->할인율 경우의 수 list [(0.1,0.1,0.2,0.4),(..),(..)...]
    discount=list(product([0.1,0.2,0.3,0.4], repeat=len(emoticons)))
    
    maxpluscount=0
    maxperchase=0
    for case in discount:# 할인 경우의 수 ex)[0.1,0.2,0.1,0.4]형태     최대 7C4*4! ??
        pluscount=0
        perchase=0
        tmpperchase=0#각 고객의 이모티콘 임시구매금액 기록
        for u in users:#각 고객 순회    최대 100
            for i,d in enumerate(case):  #할인 경우의수 순회하면서 확인    최대 7
                if d*100>=u[0]:
                    tmpperchase+= emoticons[i]*(1-d)
                # print(tmpperchase,i,d)
            if tmpperchase >= u[1]: #금액기준넘으면 이모티콘 환불후 플러스서비스 구매
                pluscount+=1
                tmpperchase=0
            perchase+=tmpperchase   #각 고객 구매금액 총합 최신화
            tmpperchase=0   #다음고객으로넘어가기전에 임시구매금액 초기화=0
        if pluscount>maxpluscount:#플러스서비스 최대값 비교후 최신화
            maxpluscount=max(maxpluscount,pluscount)
            maxperchase=perchase
        elif pluscount==maxpluscount:#플러스서비스 값 같으면 구매금액만 최신화
            maxperchase=max(maxperchase,perchase)

    #할인율 경우의 수 list를 순회하면서 가입자수, 총액 확인하면서 맥스값 최신화 
    answer = [maxpluscount,maxperchase]
    return answer

 택배 배달과 수거하기

 

프로그래머스

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

programmers.co.kr

소요시간 : 60m

 

문제설명

>>>input

cap이라는 트럭 적재 최대 용량으로

n개의 집에 배달할 것

각 집에 diliveries 리스트 순서대로 해당 수의 물건을 배달하며 

각 집에 pickups 리스트 순서대로 해당 수의 물건을 수거한다.

>>>output

모든 집에 배달과 수거를 완료하는 최저 이동거리 result를 반환

풀이

pointer를 활용했으며, 문제를 읽으면서 가장 먼 곳부터 순회하는 것이 효과적이겠구나 하는 것을 알아내는 것이 핵심이다. 

그 외에는 단순 구현이라고 생각한다. 

 

배달 및 수거를 위해 이동해야 하는 최대 거리인 length를 선언한다. 

매 이동마다 최대 cap의 배송을 하고 최대 cap의 수거를 한다. 

pointer로 pickidx, putidx를 선언하는데 이는 배달 및 수거를 하러 갈 가장 먼 거리를 뜻한다. (더이상 배달, 수거할 것이 없으면 0,0이 됨)

순회를 진행하며 lengthpickidx, putidx 중에 큰 값으로 최신화된다. 왜냐하면 배달이든 수거든 가장 먼 곳에 먼저 들러야 하기 때문이다.

pickidx, putidx 가 모두 0,0 이면 배달 및 수거할 것이 더이상 없다는 의미이기에 순회를 종료한다.

 

참고사항

* deliveries와 pickups의 마지막 요소(index = -1)가 0이 되면 지속적으로 pop()을 해서 해당 list의 길이를 구하면 가장 먼 집까지 이동할 거리가 나오도록 한다. 

-> 예를들어 deliveries가 [1,2,3,0,0,0,1] 이었으며 5번 집에 1개의 배달을 완료했다고 가정하면 0은 전부 삭제되고 즉시 deliveries 가 [1,2,3]이 되어야 한다.

 

* 초반에 length를 선언할 시에 무작정 주어진 deliverise와 pickups의 길이를 넣으면 안된다. 가장 먼 마지막 집에 배달 및 수거할 것이 없으면 가지 않아도 되기 때문이다.

 

정답코드

# 1106~1206
# cap은 최대적재수량 n개의 집에 배달 트럭하나로 모든배달과 수거 마치고 물류창고 돌아오는 최소이동거리
# 1<=n배달집수<=100000 1<=cap적재용량<=50
# 한 집 최대 배송,수거개수 50개 박스

# 이동할때 최대한 물건 갖다주고 최대한 수거해온다.
# 먼곳부터 처리한다.


def solution(cap, n, deliveries, pickups):
    answer = 0
    while deliveries!=[] and deliveries[-1]==0:
            deliveries.pop()
    while pickups!=[] and pickups[-1]==0:
            pickups.pop()
    length=max(len(deliveries),len(pickups)) #이동할 거리 (가야하는 가장 먼 곳으로 세팅)

    putidx=n-1
    pickidx=n-1
    
    while length!=0:    #거리를 점점 줄여서 0이되면 그만
        put=cap
        pick=cap
        # print(length)
        while put!=0 and deliveries!=[]:   #배달용량 다 쓰거나 , 배달목록 전부 완료되기 전까지 
            if deliveries[-1]==0:
                deliveries.pop()
            elif put>=deliveries[-1]: #최대 배달용량이 더 크면,  deliveries[-1]=0인것 포함
                put-=deliveries[-1]
                deliveries.pop()
            elif put<deliveries[-1]:   #배달할 양이 더 크면
                deliveries[-1]-=put
                put=0
                
            # print(put)
        while deliveries!=[] and deliveries[-1]==0:
            deliveries.pop()
        # print(deliveries)
        while pick!=0 and pickups !=[]:# 수거용량 다쓰거나 , 수거목록 전부 완료되기전까지
            if pickups[-1]==0:
                pickups.pop()
            elif pick>=pickups[-1]: #최대 배달용량이 더 크면 
                pick-=pickups[-1]
                pickups.pop()
            elif pick<pickups[-1]:   #배달할 양이 더 크면
                pickups[-1]-=pick
                pick=0
                
        while pickups!=[] and pickups[-1]==0:
            pickups.pop()
        # print(pickups)
        
        
        answer+= (length)*2
        putidx=len(deliveries)
        pickidx=len(pickups)
        if (putidx==0 and pickidx==0):
            break
        length = max(putidx,pickidx)
        
    
    return answer