프로그래머스 - 디스크 컨트롤러 (heap,level3) 톺아보기 + 이유

Chan Young Jeong·2024년 1월 7일
0

알고리즘

목록 보기
11/27

프로그래머스 - 디스크 컨트롤러 (heap)

해당 문제에서 가장 중요한 부분은 어떻게 하면 대기 시간을 효율적으로 줄 일 것인가부터 시작한다. 예시에서도 볼 수 있는 것 처럼 두 경우 모두 끝나는 시간은 18초로 결국에는 모두 동일하다.
띠라서 작업의 요청부터 종료까지 걸린 시간의 평균을 가장 줄이기 위해서는 대기 시간을 줄여야 한다는 것이다.
또한 이 문제에서 또 한 가지 키포인트가 있는데 디스크가 쉬고 있으면 안 되는 것이다. 일이 있는 한 무조건 해야 한다는 것이다.
이 부분을 잘 기억하고 있자.



이 문제를 푸는 나의 사고는 다음과 같았다.
가장 먼저 무조건 처음 시작할 때는 가장 먼저 요청이 들어온 잡을 실행할 것이다. 그렇게 되면 예시에서 A가 가장 먼저 실행 될 것이다. 그렇게 되면 A는 3초에 끝나고 3초 시점에 무조건 B와 C 중에 하나를 선택해서 실행해야한다. 이 때 무엇을 선택하야할까? 이게 이 문제의 키포인트다. 앞에서 대기시간을 줄이는 방향으로 잡을 골라야 한다. 이 때 현재 3초인 시점에서 B와 C 중 어느 것을 선택해도 지금까지 기다린 시간( B : 3 - 1 = 2ms ,C : 3 - 2 = 1ms ) 은 무조건 적으로 대기해야하는 시간이다. 따라서 둘 중 소요 시간을 짧은 것을 골라야 선택 받지 못 한 다른 일들의 대기 시간이 줄어든다. (즉, 소요 시간이 긴 걸 고르면 선택 받지 못 한 일들이 그만큼 다 기다려야 하기 때문)

이를 좀 더 일반화 하면

만약 수행할 수 있는 작업 a , b, c, d 가 있다고 하자
이때 만약 작업시간이 가장 긴 a를 수행하게 되면 시작시간과 상관없이 b, c, d 가 기다리는 시간이 a의 긴 수행시간을 더해서 기다려야하기 때문에 전체 평균은 증가할 수 밖에 없는 것이다.
반대로 만약 작업시간이 가장 짧은 b를 수행하게 되면
나머지들의 대기시간도 짧아지고, 전체 평균은 이것을 선택함으로써 손해는 없다는 것을 알 수 있다.
https://nsgg.tistory.com/186

따라서 이 문제는 그리디 알고리즘과 자료구조(힙)이 사용된 문제이다. 그리디인 이유는 현재 상황에서 가장 큰 이윤을 좇아야 하기 때문이고,

탐욕 선택 속성(Greedy Choice Property) : locally optimal choice lead to a globally optimal solution.
최적 부분 구조(Optimal Substructure) : the optimal solution to a problem incorporates the optimal solution to subproblems.
그리디 공부하러가기

다음과 같은 그리디 알고리즘의 속성을 만족한다.

또한 자료구조(힙)이 사용되는 것은 우선순위큐 즉, 최소힙을 사용해서 대기 중인 일 중 소요시간이 최소인 잡을 구해야하기 떄문이다.

from heapq import heappush,heappop
def solution(jobs):
    answer = 0
    jobs.sort(key= lambda x : (x[0],x[1]))
    prev_end_time = -1
    end_time = 0
    heap = []
    i = 0
    now = 0
    while i < len(jobs):
        
        for j in jobs:
            if prev_end_time < j[0] <= end_time:
                heappush(heap,(j[1],j[0]))
                
        if len(heap):
            cost, start_time = heappop(heap)
            prev_end_time = end_time
            answer += (cost + end_time-start_time) # 수행시간 + 대기시간
            end_time += cost
            i += 1
        else:
            end_time += 1  
            
    answer = answer // len(jobs)
    return answer

# [[0, 3], [1, 9], [2, 6]]
# [1,9] , [2,6] 요청이 왔을 때 어떤 것을 처리하는 게 효율적인가?
# 실행시간은 같기 때문에, 대기 시간을 줄여야함
#  잡1이 끝난 시점에 잡2,잡3을 할 수 있다. 이 때 다른 일들의 대기시간을 최소화 할 수 있는 방#  법은 소요시간이 가장 짧은 것을 수행해서 최소한 대기시간을 줄이는 것

0개의 댓글