문제 링크

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

 

문제 설명

점심시간에 도둑이 들어, 일부 학생이 체육복을 도난당했습니다. 다행히 여벌 체육복이 있는 학생이 이들에게 체육복을 빌려주려 합니다. 학생들의 번호는 체격 순으로 매겨져 있어, 바로 앞번호의 학생이나 바로 뒷번호의 학생에게만 체육복을 빌려줄 수 있습니다. 예를 들어, 4번 학생은 3번 학생이나 5번 학생에게만 체육복을 빌려줄 수 있습니다. 체육복이 없으면 수업을 들을 수 없기 때문에 체육복을 적절히 빌려 최대한 많은 학생이 체육수업을 들어야 합니다.

전체 학생의 수 n, 체육복을 도난당한 학생들의 번호가 담긴 배열 lost, 여벌의 체육복을 가져온 학생들의 번호가 담긴 배열 reserve가 매개변수로 주어질 때, 체육수업을 들을 수 있는 학생의 최댓값을 return 하도록 solution 함수를 작성해주세요.

 

제한사항

  • 전체 학생의 수는 2명 이상 30명 이하입니다.
  • 체육복을 도난당한 학생의 수는 1명 이상 n명 이하이고 중복되는 번호는 없습니다.
  • 여벌의 체육복을 가져온 학생의 수는 1명 이상 n명 이하이고 중복되는 번호는 없습니다.
  • 여벌 체육복이 있는 학생만 다른 학생에게 체육복을 빌려줄 수 있습니다.
  • 여벌 체육복을 가져온 학생이 체육복을 도난당했을 수 있습니다. 이때 이 학생은 체육복을 하나만 도난당했다고 가정하며, 남은 체육복이 하나이기에 다른 학생에게는 체육복을 빌려줄 수 없습니다.

 

입출력 예

n lost reserve return
5 [2, 4] [1, 3, 5] 5
5 [2, 4] [3] 4
3 [3] [1] 2

 

입출력 예 설명

예제 #1
1번 학생이 2번 학생에게 체육복을 빌려주고, 3번 학생이나 5번 학생이 4번 학생에게 체육복을 빌려주면 학생 5명이 체육수업을 들을 수 있습니다.

예제 #2
3번 학생이 2번 학생이나 4번 학생에게 체육복을 빌려주면 학생 4명이 체육수업을 들을 수 있습니다.

 

솔루션

위에 처럼 여벌의 체육복을 지닌 학생들이 오름차순으로 정렬 되어 있을때, 나보다 번호가 1번 높은 체육복이 없는 학생에게 체육복을 주면 5명이 체육복을 지니게 됨.

반면, 나보다 번호가 1번 낮은 체육복이 없는 학생에게 체육복을 주면 6명이 체육복을 지니게 됨.

따라서 여벌의 체육복을 지닌 학생이 오름차순으로 정렬되어있을때는 먼저 자신보다 번호가 1 낮은 체육복이 없는 학생에게 체육복을 주고, 번호가 1 낮은 체육복이 없는 학생이 없으면 번호가 1 높은 체육복이 없는 학생에게 체육복을 주어야 한다. 이 순서가 바뀌게 되면 체육복을 지닌 학생 수의 최댓값을 구할 수 없다.

 

코드

sol1)

def solution(n, lost, reserve):
    u = [1]* (n+2) # 학생수보다 2 큰 리스트를 만든다. 사람수는 n명이지만 for문을 돌면서 앞에 혹은 뒷 사람에게 체육복을 빌려주는 행위(-1)을 해야 하므로 n+2개를 만든다
    for i in reserve:  # O(n)
        u[i] +=1 # 여벌의 옷을 가지고 있는 학생들은 체육복의 수가 2임 
    for i in lost:     # O(n)
        u[i] -= 1 # 옷을 가지고 있지 않은 학생들은 체육복의 수가 0임
    
    for j in range(1,n+1): # for문은 1번부터 n번의 학생들만 돈다  # O(n)
                           # 사람이 오름차순으로 정렬되어있으므로 탐욕법을 적용하려면 나보다 번호가 1 낮은 사람이 체육복을 가지고 있는지를 먼저 살펴야 함   
        if u[ j - 1] == 0 and u[j] == 2:  # 내가 2벌을 가지고 있고 나보다 번호가 1 작은 사람이 체육복이 없다면 빌려준다
            u[j-1 : j+1] = [1,1]
        elif  u[j] == 2 and u[j + 1] ==0:  # 내가 2벌을 가지고 있고 나보다 번호가 1 큰 사람이 체육복이 없다면 빌려준다
            u[j : j+2] = [1, 1]
            
    return len([x for x in u[1:-1] if x > 0]) # 1번 부터 n번의 학생들 중에서 숫자가 1인 사람들만 모은 리스트의 길이를 구한다  # O(n)

sol2) n은 매우 큰데 여벌의 체육복을 가져온 학생수가 매우 작으면 해당 풀이가 더 적합하다.

def solution(n, lost, reserve):
    
    s = set(lost) & set(reserve)  # 여벌의 체육복을 가지고 왔지만 도난당해서 다른사람에게 빌려줄 수 없는 사람들
    lost_only = set(lost) - s # 체육복을 빌려야 하는 사람들
    reserve_only = set(reserve) - s # 여벌의 체육복을 가진 사람들
    
    for x in sorted(reserve_only):   # 여벌의 체육복을 지닌 사람들을 오름차순으로 정렬했으므로 탐욕법을 적용하려면 나보다 번호가 1 낮은 사람이 체육복을 가지고 있는지를 먼저 살펴야 함   # O(KlogK)
        if  x-1 in lost_only:
            lost_only.remove(x-1)
        elif x+1 in lost_only:
            lost_only.remove(x+1)
    return n - len(lost_only)

 

 

출처: 프로그래머스 코딩 테스트 연습, https://school.programmers.co.kr/learn/challenges

'프로그래머스 > lv1' 카테고리의 다른 글

lv1 완주하지 못한 선수  (1) 2022.09.22
lv1 예산  (0) 2022.09.21

문제 링크

문제 설명

수많은 마라톤 선수들이 마라톤에 참여하였습니다. 단 한 명의 선수를 제외하고는 모든 선수가 마라톤을 완주하였습니다.

마라톤에 참여한 선수들의 이름이 담긴 배열 participant와 완주한 선수들의 이름이 담긴 배열 completion이 주어질 때, 완주하지 못한 선수의 이름을 return 하도록 solution 함수를 작성해주세요.

제한사항

  • 마라톤 경기에 참여한 선수의 수는 1명 이상 100,000명 이하입니다.
  • completion의 길이는 participant의 길이보다 1 작습니다.
  • 참가자의 이름은 1개 이상 20개 이하의 알파벳 소문자로 이루어져 있습니다.
  • 참가자 중에는 동명이인이 있을 수 있습니다.

입출력 예

participant completion return
["leo", "kiki", "eden"] ["eden", "kiki"] "leo"
["marina", "josipa", "nikola", "vinko", "filipa"] ["josipa", "filipa", "marina", "nikola"] "vinko"
["mislav", "stanko", "mislav", "ana"] ["stanko", "ana", "mislav"] "mislav"

입출력 예 설명

예제 #1
"leo"는 참여자 명단에는 있지만, 완주자 명단에는 없기 때문에 완주하지 못했습니다.

예제 #2
"vinko"는 참여자 명단에는 있지만, 완주자 명단에는 없기 때문에 완주하지 못했습니다.

예제 #3
"mislav"는 참여자 명단에는 두 명이 있지만, 완주자 명단에는 한 명밖에 없기 때문에 한명은 완주하지 못했습니다.

코드

sol1) 딕셔너리를 이용한 풀이

def solution(participant, completion):
    temp = {} # key,value를 가진 딕셔너리 이용

    #딕셔너리에 참가자 이름(key)과 해당 이름 사람수(value) 넣기 
    for i in participant :
        if i in temp : # 딕셔너리에서 in을 쓰면 key값이 있는지를 묻는 것
            temp[i]+=1
        else: 
            temp[i] =1
    
    #완주자 이름(key)의 value가 1이면 지우기, 동명이인이면 -1  
    for i in completion :
        if temp[i]==1 : 
            del temp[i]
        else : 
            temp[i] -=1

    #딕셔너리를 리스트로 바꾸고 가장 첫번째꺼 리턴(어차피 하나뿐)
    return list(temp.keys())[0]

sol2) 딕셔너리의 get을 이용한 풀이

  • dic.get(key) : key값에 대응하는 value값을 출력한다. 이는 dic[key]와 같으나 만약 없는 key값을 출력하라고 하면 dic[key]는 error를 출력하고, dic.get(key)는 None을 출력함. 만약 해당 key가 없을 때 반환되는 값을 바꾸 고 싶다면, get() 메소드의 두번째 인자로 주면 됨.
def solution(participant, completion):
    dic = {}
    for x in participant:
        dic[x] = dic.get(x,0) + 1 # dic에 key값으로 x가 있으면 x에 대응하는 value를 출력하고 없으면 0을 출력 #O(n)
    for x in completion:
        dic[x] -= 1                # O(n)
    sol = [k for k, v in dic.items() if v > 0]  #O(n)
    answer = sol[0]
    return answer

 

sol3) 딕셔너리를 사용한 후 sorted를 이용한 풀이

def solution(participant, completion):
    dic = {}
    for i in participant:
        if i not in dic:
            dic[i] = 1
        else:
            dic[i] += 1
    for j in completion:
        dic[j] -= 1
        
    sol = sorted(dic.items(), key = lambda x: x[1], reverse = True)
    return sol[0][0]

sol4) zip을 이용한 풀이

  • zip : 배열을 같은 인덱스끼리 짝지어준다. 만약 배열의 길이가 다를 경우 같은 인덱스끼리만 짝지어주고, zip 객체에서 나머지 인덱스는 제외된다.
def solution(participant, completion):
    participant.sort()  # O(nlogn)
    completion.sort()   # O(nlogn)
    for p,c in zip(participant, completion):
        if p != c:
            return p
    return participant[-1] # 모두 일치하면 사람수가 하나 더 많은 participant의 마지막 번호의 사람이 완주못한 것

sol5) Counter()를 이용한 풀이

  • collections.Counter: 원소의 수를 딕셔너리 형태로 출력함. 딕셔너리는 차집합이 불가능하지만 Counter내의 딕셔너리는 차집합이 가능함.
import collections
def solution(participant, completion):
    sol=collections.Counter(participant) - collections.Counter(completion)
    return list(sol.keys())[0]

sol6) 해시함수 이용 2번째 방법

  • hash('a') # 해당 value에 해당하는 hash값을 출력해줌

       >>> 3338796687179829302

def solution(participant , completion):
    Dic ={}
    sum = 0
    for part in participant:
        Dic[hash(part)] = part  # {숫자:'참가자'} 형태의 딕셔너리를 만듦
        sum += hash(part)       # 해당 참가자에 해당하는 key겂인 숫자를 더해준다
        
    for comp in completion:
        sum -=hash(comp)       # 완주한 사람에서 해당하는 key값인 숫자를 빼준다
    return Dic[sum]          # 남은 숫자의 key에 대응하는 값이 완주 못한 사람임

 

 

출처: 프로그래머스 코딩 테스트 연습, https://school.programmers.co.kr/learn/challenges

'프로그래머스 > lv1' 카테고리의 다른 글

lv1 체육복  (0) 2022.09.22
lv1 예산  (0) 2022.09.21

문제 링크

문제 설명

S사에서는 각 부서에 필요한 물품을 지원해 주기 위해 부서별로 물품을 구매하는데 필요한 금액을 조사했습니다. 그러나, 전체 예산이 정해져 있기 때문에 모든 부서의 물품을 구매해 줄 수는 없습니다. 그래서 최대한 많은 부서의 물품을 구매해 줄 수 있도록 하려고 합니다.

물품을 구매해 줄 때는 각 부서가 신청한 금액만큼을 모두 지원해 줘야 합니다. 예를 들어 1,000원을 신청한 부서에는 정확히 1,000원을 지원해야 하며, 1,000원보다 적은 금액을 지원해 줄 수는 없습니다.

부서별로 신청한 금액이 들어있는 배열 d와 예산 budget이 매개변수로 주어질 때, 최대 몇 개의 부서에 물품을 지원할 수 있는지 return 하도록 solution 함수를 완성해주세요.

 

제한 사항

  • d는 부서별로 신청한 금액이 들어있는 배열이며, 길이(전체 부서의 개수)는 1 이상 100 이하입니다.
  • d의 각 원소는 부서별로 신청한 금액을 나타내며, 부서별 신청 금액은 1 이상 100,000 이하의 자연수입니다.
  • budget은 예산을 나타내며, 1 이상 10,000,000 이하의 자연수입니다.

입출력 예

d budget result
[1,3,2,5,4] 9 3
[2,2,3,3] 10 4

 

입출력 예 설명

입출력 예 #1
각 부서에서 [1원, 3원, 2원, 5원, 4원]만큼의 금액을 신청했습니다. 만약에, 1원, 2원, 4원을 신청한 부서의 물품을 구매해주면 예산 9원에서 7원이 소비되어 2원이 남습니다. 항상 정확히 신청한 금액만큼 지원해 줘야 하므로 남은 2원으로 나머지 부서를 지원해 주지 않습니다. 위 방법 외에 3개 부서를 지원해 줄 방법들은 다음과 같습니다.

  • 1원, 2원, 3원을 신청한 부서의 물품을 구매해주려면 6원이 필요합니다.
  • 1원, 2원, 5원을 신청한 부서의 물품을 구매해주려면 8원이 필요합니다.
  • 1원, 3원, 4원을 신청한 부서의 물품을 구매해주려면 8원이 필요합니다.
  • 1원, 3원, 5원을 신청한 부서의 물품을 구매해주려면 9원이 필요합니다.

3개 부서보다 더 많은 부서의 물품을 구매해 줄 수는 없으므로 최대 3개 부서의 물품을 구매해 줄 수 있습니다.

입출력 예 #2
모든 부서의 물품을 구매해주면 10원이 됩니다. 따라서 최대 4개 부서의 물품을 구매해 줄 수 있습니다.

 

코드

sol1)

# budget에서 d의 원소가 작은것부터 뺌. budget이 0보다 작아질때까지 뺌
def solution(d, budget):
    cnt = 0
    d.sort()
    for i in d:
        budget -= i
        if budget < 0:
            break
        cnt +=1
    return cnt

sol2) pop을 이용한 풀이

def solution(d, budget):
    d.sort()  # 오름차순 정렬
    while budget < sum(d): # 위와 반대로 가장 큰 것들을 빼면서 남은 d의 원소들의 길이를 return함 
        d.pop()  # 가장 왼쪽의 원소를 삭제함
    return len(d)

 

출처: 프로그래머스 코딩 테스트 연습, https://school.programmers.co.kr/learn/challenges

'프로그래머스 > lv1' 카테고리의 다른 글

lv1 체육복  (0) 2022.09.22
lv1 완주하지 못한 선수  (1) 2022.09.22

+ Recent posts