[알고리즘]프로그래머스, 과제 진행하기(구현)

Lee Yongin·2023년 8월 29일
0

알고리즘

목록 보기
3/8

LV2 연습문제를 풀어보았다.
https://school.programmers.co.kr/learn/courses/30/lessons/176962

문제의 핵심조건은
1. 다음과제 시작시간까지 현재과제가 미완료되면 미루고 다음과제를 시작한다.
2. 다음과제 시작시간까지 현재과제가 완료되면 최근 미뤄둔 과제부터 한다.->스택 사용
+시간계산이 필요함(문제에선 HH:MM으로 주어졌지만 분 단위로 바꿔서 하는 게 더 편리했다.)

나의 코드

단순하게 시간비교를 하면서 스택을 이용한 구현으로 갔다. 함수로 정리한다고는 했지만 좀 길다.

def calculMinute(string):
    hour, min = map(int, string.split(':'))
    time = hour * 60 + min
    return time

def pushInStack(limit_time, play_time,name,stack, answer, real_time):
    if(limit_time < play_time):
        new_time = play_time - limit_time
        stack.append((name, new_time))
        real_time += limit_time #제한시간까지만 채워짐
    elif(limit_time > play_time):
        answer.append(name)
        real_time += play_time# 수행한 만큼만 시간이 감
    elif(limit_time == play_time):
        answer.append(name)
        real_time += play_time# 수행한 만큼만 시간이 감
    return real_time
        
def solution(plans):
    answer = []
    stack = []
    plans.sort(key=lambda x:x[1])
    
    real_time = calculMinute(plans[0][1]) #현재시간 초기화

    for i in range(len(plans)-1):
        name,cur_time, need_time = plans[i][0], calculMinute(plans[i][1]), int(plans[i][2])
        next_time = calculMinute(plans[i+1][1]) #다음과제 시작시간
        limit_time = next_time - cur_time
        real_time = cur_time
        #다음 과제 시작시간까지 현재 과제를 못 마칠 것으로 예상됨
        if(limit_time < need_time):
            real_time = pushInStack(limit_time, need_time, name, stack, answer, real_time)
        #꽉 채워서 현재 과제를 수행할 것으로 예상됨
        elif(limit_time == need_time):
            real_time = pushInStack(limit_time, need_time, name, stack, answer, real_time)
        #현재 과제를 해도 시간이 남을 것으로 예상됨
        elif(limit_time > need_time):
            real_time = pushInStack(limit_time, need_time, name, stack, answer, real_time)
            while stack:
                name, time = stack.pop()
                updated_limit = (next_time-real_time)
                #여분과제 제한시간이 남은 시간보다 커서 다 못마칠 경우
                if(time > updated_limit):
                    real_time = pushInStack(updated_limit, time, name, stack, answer, real_time)
                    #다음 과제로 넘어가기
                    break
                #시간이 딱 맞을 경우
                elif(time == updated_limit):
                    real_time = pushInStack(updated_limit, time, name, stack, answer, real_time)
                    #다음과제로 넘어가기
                    break
                #또다른 여분 과제를 할 수 있을 경우
                elif(time < updated_limit):
                    real_time = pushInStack(updated_limit, time, name, stack, answer, real_time)
        
    #마지막 과제는 무조건 수행완료됨
    answer.append(plans[-1][0])

    while stack:
        name, time = stack.pop()
        answer.append(name)
    return answer

더 좋은 코드

다른 사람의 풀이를 보고 선정했다. 주관적이지만 더 좋은 코드라고 생각한다.
핵심 아이디어는 해당 과제가 '언제 끝날지'이다. 따라서 언제 끝날지 시간갱신을 한 다음에, sort()함수로 완료순으로 답을 도출한다.

아이디어 설명

1.정렬 및 시간 전처리를 한 [["music", "740", "40"], ["computer", "750", "100"],["science", "760", "50"], ["history", "840", "30"]] 이 상태에서 과제의 완료시간을 계산한다. 그 다음 과제의 시작시간과 비교했을 때 그 시간을 넘어간다면 미뤄지고, 넘어가지 않으면 미뤄지지 않는다.
2.미뤄질 경우, 새로 시작하는 과제의 수행시간만큼 미뤄질 것이므로 미뤄지는 과제의 완료시간은 더 늘어난다.
3.반면 미뤄지지 않는 경우 과제를 완수했다는 뜻이므로 과제의 완료시간은 더 이상 갱신되지 않는다.
4.과제의 완료시간을 기준으로 lst를 sort 하면, 간단하게 해결된다.

***주의할 게 시간을 더한다고 해서 과제의 완료시간은 정확하게 계산되지 않는다. 대충 미뤄지냐, 안 미뤄지냐를 판단하기 위한 상대적인 값이다. (이런 점이 생각하기 힘든 아이디어 였다.)

def solution(plans):
    plans = sorted(map(lambda x: [x[0], int(x[1][:2]) * 60 + int(x[1][3:]), int(x[2])], plans), key=lambda x: -x[1])

    lst = []
    while plans:
        x = plans.pop()
        for i, v in enumerate(lst):
            if v[0] > x[1]:
                lst[i][0] += x[2]
        lst.append([x[1] + x[2], x[0]])
    lst.sort()

    return list(map(lambda x: x[1], lst))
profile
f1을 좋아하는...🏆 f1처럼 빠르고 정확한 걸 좋아하는 안드로이드 개발자

0개의 댓글