프로그래머스 문제 9, 10

4 minute read

야간 전술보행

전쟁에 참여한 화랑이는 적군의 기지에 침투하여 정보를 훔쳐오는 임무를 받았습니다. 화랑이는 야간 전술 보행을 이용하여 직진하며, 야간 전술 보행은 1m/s의 일정한 속도로 나아갈 수 있습니다. 화랑이의 침입 경로에는 경비병들이 각자 일부 구간들을 감시하고 있습니다. 각각의 경비병들이 감시하는 구간은 서로 겹치지 않으며, 일정 시간 동안 근무 후 일정 시간 동안 휴식을 취하는 과정을 반복합니다. 화랑이가 지나가고 있는 위치를 감시하는 경비병이 근무 중이라면 화랑이는 경비병에게 발각되어 즉시 붙잡히게 됩니다. 하지만 해당 위치를 감시하는 경비병이 휴식을 취하고 있으면 화랑이는 무사히 해당 위치를 지나갈 수 있습니다. 경비병의 근무 정보를 모르는 화랑이는 쉬지 않고 전진을 하며, 화랑이가 출발할 때 모든 경비병들이 동시에 근무를 시작합니다. 예를 들어, 적군 기지까지의 거리가 10m이고 2명의 경비병들이 근무를 시작한다고 가정합시다. 첫 번째 경비병의 감시 구간은 화랑이의 출발 위치로부터 3m부터 4m까지이고, 두 번째 경비병의 감시 구간은 화랑이의 출발 위치로부터 5m부터 8m까지입니다. 첫 번째 경비병의 근무 및 휴식 시간은 각각 2초, 5초를 반복하며, 두 번째 경비병의 근무 및 휴식 시간은 각각 4초, 3초를 반복합니다. 이 경우 출발지로부터 화랑이의 위치에 따른 두 경비병의 상태는 아래 표와 같습니다. 첫 번째 경비병이 감시하는 3m ~ 4m 구간을 화랑이는 3초일 때 진입하지만, 첫 번째 경비병은 2초간의 근무를 마치고, 휴식을 시작했으므로, 화랑이는 붙잡히지 않습니다. 하지만 두 번째 경비병이 감시하는 5m ~ 8m 구간에서 화랑이가 8m 지점에 진입했을 때, 두 번째 경비병이 3초간의 휴식을 마치고 근무를 시작하므로 화랑이는 붙잡히게 됩니다. 화랑이의 현재 위치와 적군 기지 사이의 거리를 나타내는 정수 distance, 각 경비병의 감시 구간을 담은 2차원 정수 배열 scope, 같은 순서로 각 경비병의 근무 시간과 휴식 시간을 담은 2차원 정수 배열 times가 주어질 때, 화랑이가 경비를 피해 최대로 이동할 수 있는 거리를 return 하는 solution 함수를 완성하세요.

입력: scope=[[7, 8], [4, 6], [11, 10]], times=[[2, 2], [2, 4], [3, 3]]

출력: 12

내 풀이

def solution(distance, scope, times):
    guard_list = []
    for time in times:
        guard = []
        patrol = time[0]
        rest = time[1]
        while len(guard) < distance:
            guard += patrol*[True]
            guard += rest*[False]
        guard_list.append(guard[:distance])
    
    for i, s in enumerate(scope):
        start = s[0]-1
        end = s[1]-1
        if True in guard_list[i][start:end+1]:
            distance = min(distance, start + guard_list[i][start:end+1].index(True) + 1)
        
    return distance
  • 시간초과 에러가 발생하였다.

풀이

def solution(distance, scope, times):
    list = [distance]
    for i in range(len(scope)):
        start, end = sorted(scope[i])
        work, rest = times[i]

        while start <= end:
            check = start % (work + rest) # 근무,휴식 패턴 파악하고
            if 0 < check and check <= work: # 남은 일수가 work 일수보다 낮으면 근무 인 날에 지나 감
                list.append(start) # 걸린 시간을 추가 해주고
                break   # 게임끝
            start += 1

    return sorted(list)[0]
  • 경비병의 감시구간을 하나씩 반복하면서 근무인 날에 화랑이가 지나갔는지 여부를 검사한다.
  • 만약 근무인 날에 화랑이가 지나갔으면 근무인 날을 list에 추가하고 그 중에서 최소 값을 리턴한다.

롤케이크 자르기

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

출력: 2

내 풀이

from collections import Counter

def solution(topping):
    brother = Counter(topping)
    chulsoo = set()
    ans = 0
    for i in topping:
        brother[i] -= 1
        chulsoo.add(i)
        if brother[i] == 0:
            brother.pop(i)
        if len(brother) == len(chulsoo):
            ans += 1
        if len(brother) < len(chulsoo):
            break
            
    return ans
  • brother와 chulsoo 변수를 만들어서 원소의 수를 비교하고 수가 같으면 ans에 1을 더해준다.

풀이 1

import bisect, itertools, collections

def solution(info, query):
    infomap = collections.defaultdict(list)
    binarys = list(itertools.product((True, False), repeat=4))
    for inf in info:
        inf = inf.split()
        for binary in binarys:
            key = ''.join([inf[i] if binary[i] else '-' for i in range(4)]) 
            infomap[key].append(int(inf[4]))

    for k in infomap.keys():
        infomap[k].sort()

    answers = []
    for q in query:
        l,_,p,_,c,_,f, point = q.split()
        key = ''.join([l,p,c,f])
        # 1,2,3번째 조건에 맞는 key의 value를 찾고 그 중에서 문의 조건에서 설정한 점수보다 낮은 점수의 개수를 찾음
        i = bisect.bisect_left(infomap[key], int(point))
        answers.append(len(infomap[key]) - i)

    return answers
  • 하나의 info에서 나올 수 있는 16가지의 key를 만들어서 infomap[key]에 값을 추가해준다.
  • 이진 검색을 위해 infomap의 값들을 정렬한다.
  • query의 값을 key로 만들고 이진 탐색으로 point 이상의 값 개수를 구한다.

Comments