프로그래머스 Level2 : 기능개발

프로그래머스 팀에서는 기능 개선 작업을 수행 중입니다. 각 기능은 진도가 100%일 때 서비스에 반영할 수 있습니다.

또, 각 기능의 개발속도는 모두 다르기 때문에 뒤에 있는 기능이 앞에 있는 기능보다 먼저 개발될 수 있고, 이때 뒤에 있는 기능은 앞에 있는 기능이 배포될 때 함께 배포됩니다.

먼저 배포되어야 하는 순서대로 작업의 진도가 적힌 정수 배열 progresses와 각 작업의 개발 속도가 적힌 정수 배열 speeds가 주어질 때 각 배포마다 몇 개의 기능이 배포되는지를 return 하도록 solution 함수를 완성하세요.

제한 사항

  • 작업의 개수(progresses, speeds배열의 길이)는 100개 이하입니다.
  • 작업 진도는 100 미만의 자연수입니다.
  • 작업 속도는 100 이하의 자연수입니다.
  • 배포는 하루에 한 번만 할 수 있으며, 하루의 끝에 이루어진다고 가정합니다. 예를 들어 진도율이 95%인 작업의 개발 속도가 하루에 4%라면 배포는 2일 뒤에 이루어집니다.

입출력 예

progresses speeds return
[93,30,55] [1,30,5] [2,1]

입출력 예 설명

첫 번째 기능은 93% 완료되어 있고 하루에 1%씩 작업이 가능하므로 7일간 작업 후 배포가 가능합니다. 두 번째 기능은 30%가 완료되어 있고 하루에 30%씩 작업이 가능하므로 3일간 작업 후 배포가 가능합니다. 하지만 이전 첫 번째 기능이 아직 완성된 상태가 아니기 때문에 첫 번째 기능이 배포되는 7일째 배포됩니다. 세 번째 기능은 55%가 완료되어 있고 하루에 5%씩 작업이 가능하므로 9일간 작업 후 배포가 가능합니다.

따라서 7일째에 2개의 기능, 9일째에 1개의 기능이 배포됩니다.

해설

처음에 개발하고, 그 후 배포하는 형태로 코드를 작성했다. 처음에 다음처럼 작성했는데, list(map(lambda))도 동작이 iterable하므로 for문과 같다고 생각하니 while안에 for문이 3개라 줄여봤다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def solution(progresses, speeds):
    answer = []
    while sum(speeds) != 0:
        progresses = list(map(lambda x, y : x+y, progresses, speeds)) #하루 개발       
        if progresses[0] >= 100: #우선순위 높은 기능 개발 완료되면 배포
            speeds = list(map(lambda x, y : 0 if x >= 100 else y, progresses, speeds))
            idx = 0
            for i in range(len(speeds)):
                if speeds[i] == 0:
                    idx = i
                else: break
            total = idx + 1
            progresses = progresses[idx+1:]#배포된 후 리스트에서 제거
            speeds = speeds[idx+1:]        
            answer.append(total)
    return answer

줄이고 나니까 개발하는 것도 하나의 for문으로 작성할 수 없을까 고민해봤는데, 오히려 코드가 복잡해져서 접었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
def solution(progresses, speeds):
    answer = []
    while sum(speeds) != 0:
        progresses = list(map(lambda x, y : x+y, progresses, speeds)) #하루 개발       
        if progresses[0] >= 100: #우선순위 높은 기능 개발 완료되면 배포
            complete = 0
            for i in progresses:
                if i>= 100 : complete += 1
                else: break
            answer.append(complete)
            progresses = progresses[complete:]#배포된 후 리스트에서 제거
            speeds = speeds[complete:]
    return answer

근데 다른사람 풀이를 보니까 대단하더라. 어떻게 생각해내는거지?

1
2
3
4
5
6
7
8
def solution(progresses, speeds):
    Q=[]
    for p, s in zip(progresses, speeds):
        if len(Q)==0 or Q[-1][0]<-((p-100)//s):#(p-100)//s는 다 개발되기까지 걸리는 시간
            Q.append([-((p-100)//s),1]) #다음 기능이 개발되지 않으면
        else:
            Q[-1][1]+=1 #다음 기능이 개발되었으면
    return [q[1] for q in Q]

프로그래머스 Level2 : 다리를 지나는 트럭

트럭 여러 대가 강을 가로지르는 일 차선 다리를 정해진 순으로 건너려 합니다. 모든 트럭이 다리를 건너려면 최소 몇 초가 걸리는지 알아내야 합니다. 트럭은 1초에 1만큼 움직이며, 다리 길이는 bridge_length이고 다리는 무게 weight까지 견딥니다. ※ 트럭이 다리에 완전히 오르지 않은 경우, 이 트럭의 무게는 고려하지 않습니다.

예를 들어, 길이가 2이고 10kg 무게를 견디는 다리가 있습니다. 무게가 [7, 4, 5, 6]kg인 트럭이 순서대로 최단 시간 안에 다리를 건너려면 다음과 같이 건너야 합니다.

경과 시간 다리를 지난 트럭 다리를 건너는 트럭 대기 트럭
0 [] [] [7,4,5,6]
1~2 [] [7] [4,5,6]
3 [7] [4] [5,6]
4 [7] [4,5] [6]
5 [7,4] [5] [6]
6~7 [7,4,5] [6] []
8 [7,4,5,6] [] []

따라서, 모든 트럭이 다리를 지나려면 최소 8초가 걸립니다.

solution 함수의 매개변수로 다리 길이 bridge_length, 다리가 견딜 수 있는 무게 weight, 트럭별 무게 truck_weights가 주어집니다. 이때 모든 트럭이 다리를 건너려면 최소 몇 초가 걸리는지 return 하도록 solution 함수를 완성하세요.

제한 조건

  • bridge_length는 1 이상 10,000 이하입니다.
  • weight는 1 이상 10,000 이하입니다.
  • truck_weights의 길이는 1 이상 10,000 이하입니다.
  • 모든 트럭의 무게는 1 이상 weight 이하입니다.

입출력 예

bridge_length weight truck_weights return
2 10 [7,4,5,6] 8
100 100 [10] 101
100 100 [10,10,10,10,10,10,10,10,10,10] 110

해설

코드를 작성해서 잘 돌아갔는데, 계속 시간초과가 떴다. sum이 $O(n)$이라서 원래 사용하던 sum(bridge)weight관리로 바꿔주니 잘 돌아갔다. 근데 while문이 좀 거슬렸다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def solution(bridge_length, weight, truck_weights):
    bridge = [0] * bridge_length
    origin = weight
    num = 0
    while True:
        num += 1
        weight += bridge.pop(0) #도착하면 무게 더해줌
        if truck_weights !=[]:
            if truck_weights[0] <= weight:
                bridge.append(truck_weights.pop(0))
                weight -= bridge[-1] #다리에 올라와 있으면 무게 빼줌
            else: bridge.append(0)
        if weight == origin: break #무게로 while문 관리
    return num

다른 사람풀이를 참고하니, 아래처럼 써서 사용했다. 생각해보니 bridge가 텅 비는 시점이 모든 트럭이 다리를 건넌 시점이랑 똑같더라.

1
2
3
4
5
6
7
8
9
10
11
12
def solution(bridge_length, weight, truck_weights):
    bridge = [0] * bridge_length
    num = 0
    while bridge:
        num += 1
        weight += bridge.pop(0) #도착하면 무게 더해줌
        if truck_weights !=[]:
            if truck_weights[0] <= weight:
                bridge.append(truck_weights.pop(0))
                weight -= bridge[-1] #다리에 올라와 있으면 무게 빼줌
            else: bridge.append(0)
    return num

Leave a comment