[프로그래머스] lv2 #42584 주식가격 / #42586 기능개발 / #42583 다리를 지나는 트럭

스택과 큐 개념을 연습하기 위하여 3개의 연습문제(주식가격, 기능개발, 다리를 지나는 트럭문제)를 풀었다.

문제모음


1. #42584 주식가격

문제

초 단위로 기록된 주식가격이 담긴 배열 prices가 매개변수로 주어진다. 이 때, 주식의 가격이 떨어지지 않은 기간이 몇 초인지를 return 하도록 solution 함수를 완성하라.


제한사항
  • prices의 각 가격은 1 이상 10,000 이하인 자연수
  • prices의 길이는 2 이상 100,000 이하


입출력 예
prices return
[1, 2, 3, 2, 3] [4, 3, 1, 1, 0]
  • 3초 시점의 ₩3은 1초뒤에 가격이 떨어진다. 따라서 1초간 가격이 떨어지지 않은 것으로 본다.
  • 5초 시점의 ₩3은 0초간 가격이 떨어지지 않는다고 본다. (return의 마지막 값은 무조건 0)


풀이

def Solution(prices):
    def solution(prices):
        answer = []
        for i in range(len(prices)):
            st_pr = prices[i]
            cnt = 0
            j = i
            while j < (len(prices) - 1): # 마지막 값은 비교가 무의미하므로 이렇게 조건을 달아줌
                if st_pr > prices[j]:
                    break
                else:
                    j += 1
                    cnt += 1
            answer.append(cnt)
        return answer
해설

핵심은 prices의 값들 각각을 기준값으로 잡고, prices 내에서 기준값보다 작은 값이 나타날 때 까지 리스트를 검사하며 검사한 값의 갯수를 저장하여, 이를 answer에 반영한다.


  • st_pr은 기준값이다. prices에서 for문을 돌려 각 값을 순서대로 하나씩 기준값으로 잡아준다.
  • j는 기준값 이후의 값들을 검사하기 위한 for문 인자이다.
  • cnt는 기준값 미만의 값이 나올때 까지 코드를 반복한 횟수를 저장하며, 이것이 곧 answer의 값으로 추가된다.
  • answer의 마지막 값은 무조건 0이므로, 코드 중간의 while문에 들어가지 않도록 조건을 걸었다.


스택을 활용해보고자 했으나 코드 실행 시간을 감안하면 for문과 while문을 통해 효율적으로 짜는게 더 좋다고 판단하여 이렇게 문제를 풀었다.


2. #42586 기능개발

문제

먼저 배포되어야 하는 순서대로 작업의 진도가 적힌 정수 배열 progresses와 각 작업의 개발 속도가 적힌 정수 배열 speeds가 주어진다.

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

각 배포시마다 몇 개의 기능이 배포되는지를 return 하도록 solution 함수를 완성하라.


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


입출력 예
progresses speeds return
[93, 30, 55] [1, 30, 5] [2, 1]
[95, 90, 99, 99, 80, 99] [1, 1, 1, 1, 1, 1] [1, 3, 2]
입출력 예 #1
  • 첫 번째 기능은 93% 완료되어 있고 하루에 1%씩 작업이 가능하므로 7일간 작업 후 배포가 가능하다.

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


풀이

def solution(progresses, speeds):
    answer = []
    days = []
    a = len(progresses)

    # 각 기능별로 업데이트에 걸리는 일 수 계산하여 배열로 반환(days)
    for i in range(a):
        quotient = (100 - progresses[i]) // speeds[i]
        remainder = (100 - progresses[i]) % speeds[i]
        if remainder == 0:
            day = int(quotient)
        else:
            day = int(quotient) + 1
        days.append(day)

    x = 0
    while True:
        if x == len(days):
            break
        else:
            y = x + 1
            cnt = 1
            while True:
                if y == len(days):
                    x += cnt
                    break
                else:
                    if days[x] < days[y]:
                        answer.append(cnt)
                        x += cnt
                        break
                    else:
                        y += 1
                        cnt += 1
    answer.append(cnt)
    
    return answer
해설
  • 크게 2단계로 구성되는 코드로, 먼저 각 작업을 마치는데 걸리는 기간을 저장하는 days 리스트를 만든다.

  • 이 days 리스트에서 값들을 비교하여 답을 구해내었다.

  • 아쉬운 점은, 내가 이 문제를 풀었을 때에 while문 조건을 많이 써보지 않아서 비효율적인 코드가 짜여진 느낌이 들었다.

    • 예를 들어, if y == len(days): 같은 if문을 두어 while문을 빠져나가도록 했는데 사실, 그 위에서 while y< len(days): 을 썼으면 자연스럽게 루프를 빠져나갈 수 있었을 것이다.


추가로, 답안을 제출하고 나서 다른 사람들의 풀이를 보았는데 상당히 인상 깊은 것들이 많았다.

아무래도 개인적으로 내 풀이에 아쉬움이 많었던지라 개선의 여지를 찾고자 더 열심히 풀이들을 읽어보았다.

아래에 그 중에 가장 인상깊었던 풀이를 첨부한다.


인상적인 풀이
def solution(progresses, speeds):
    Q=[]
    for p, s in zip(progresses, speeds):
        if len(Q)==0 or Q[-1][0]<-((p-100)//s): 
            Q.append([-((p-100)//s),1])
        else:
            Q[-1][1]+=1
    return [q[1] for q in Q]


3. #42583 다리를 지나는 트럭 문제

문제

트럭 여러 대가 강을 가로지르는 일차선 다리를 정해진 순으로 건너려 한다. 모든 트럭이 다리를 건너려면 최소 몇 초가 걸리는지 알아내야 하는데, 다리에는 트럭이 최대 bridge_length대 올라갈 수 있으며, 다리는 weight 이하까지의 무게를 견딜 수 있다. 단, 다리에 완전히 오르지 않은 트럭의 무게는 무시한다.

예를 들어, 트럭 2대가 올라갈 수 있고 무게를 10kg까지 견디는 다리가 있다고 하자. 무게가 [7, 4, 5, 6]kg인 4대의 트럭이 순서대로 최단 시간 안에 다리를 건너려면 다음과 같이 건너야 할 것이다.

경과 시간 다리를 지난 트럭 다리를 건너는 트럭 대기 트럭
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] [] []

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


나의 답안

def solution(bridge_length, weight, truck_weights):
    answer = 0
    q = [0] * bridge_length

    while q:
        answer += 1
        q.pop(0) 
        if truck_weights:
            if sum(q) + truck_weights[0] <= weight: 
                q.append(truck_weights.pop(0)) 
            else:
                q.append(0) 
        else:
            answer += (bridge_length - 1)
            break

    return answer
해설
  • q는 다리를 의미하며 초기에 주어진 다리길이 만큼의 갯수로 0이 채워져 있는 Queue 개념이다.
  • 트럭이 진입할 때 마다 q 맨 앞의 값이 get(=pop(0))되어 떨어져나가고, truck_weight에서 첫번쨰 트럭을 get하여 q 마지막 부분에 push한다.

  • 만약, 현재 트럭 추가시 무게제한에 걸린다면, 새로운 트럭을 추가하는 것이 아니라 그대로 0을 추가한다.

  • 이 작업을 매 시간단위마다 반복하도록 while문으로 묶어준다.

  • 마지막 트럭이 진입한 경우, 그 트럭이 빠져나가는 시간만 마지막에 더해주면 되므로 else문에 넣어 적용 후에 곧바로 루프를 탈출시킨다. (if truck_weights: 에서 truck_weights = []이므로 else문이 적용된다.)
    • 사실 이 부분이 없어도 코드가 돌아가지만, 마지막에 굳이 q에서 0을 하나씩 get하는 것 보다 효율적이므로 이렇게 코드를 구성했다.

Leave a comment