프로그래머스발행일 2025. 2. 20.원본 https://blog.naver.com/jword_/223767886870 ↗

프로그래머스 과제 진행하기

프로그래머스 과제 진행하기 — #프로그래머스 #프로그래머스과제진행하기 #개발자의도구들 사용된 언어: 코틀린, 혹은 파이썬 순서: 로직,...

#프로그래머스#Naver Blog

#프로그래머스 #프로그래머스과제진행하기 #개발자의도구들

​

​

  • 사용된 언어: 코틀린, 혹은 파이썬
  • 순서: 로직, 코드 구현, 코드 분석

아이디어

Programmers 과제진행하기(연습문제 정답율 41%)

  • 문제의도
  • 시간 데이터 처리
  • 적절한 자료구조 결정
  • Stack
javascript 코드 예제
                                    🙅 제약조건 정리

1. play time 값 1분~100분
2. 과제 갯수 1~1000개
3. 새로운 과제 > 진행중 과제
4. 진행중 이던 과제와 새로운 과제 시작시간이 같다 -> 진행중 과제가 끝난 것
5. 과제를 끝낸 순서대로 이름을 담아서 return
6. 멈춘과제가 여러개 -> 가장 최근 과제부터 진행 -> stack
javascript 코드 예제
                                    ⌛ 시간 데이터 관리
>>> 파이썬에서 변환 ?

1. "12:30" -> 1230 -> 숫자로 표현해도 무방함
2. 시간 올리기
>>> 100으로 나눈 나머지
javascript 코드 예제
                                    💡 시간의 흐름 계산

1. 1분씩 증가시키기
>>> 단순하다.
>>> 비용이 많이 발생한다.

2. 수식으로 표현하기
>>> 수식 찾기 어려워
>>> 비용을 줄일 수 있다.

필요한 method
1. 문자열 시계를 수로 변환하는 메서드
2. 문자열을 숫자로 변환 -> 기본 내장
javascript 코드 예제
                                    🔑 로직 정리

1. 초기셋팅
>>> 문자열 시간 데이터를 int로 변경
>>> playtime을 int로 변경
>>> plans를 시간 데이터 기준으로 정렬(오름차순)
>>> 초기 시간: plans[0][1]
>>> pause = 멈춤 job stack
>>> complete = 끝낸 job list(queue) anyway

2. 시간 비교시 고려사항
>>> 현재 시간 기준으로
>>> 현재 job이 끝났는지
- 끝났다면 -> pause값이 비어있는지
--- 비어잇다 : 다음 job 시간 확인
--- 비어있지 않다: pause에서 pop하여 current_job을 업데이트한다.

1차시도

javascript 코드 예제
                                    def solution(plans):
    answer = []

    print(int("20"))

    # O(n)
    for plan in plans:
        time = plan[1].replace(":", "")
        plan[1] = int(time)
        plan[2] = int(plan[2])

    # O(nlogn)
    plans.sort(key=lambda plan: plan[1])
    print(plans)

    current = [0, plans[0][1], plans[0][2]] #idx
    pause = []
    complete = []

    while 1:
        if len(complete) == len(plans):
            print("compltet!!")
            break
        print("working start!!\n>>>")

        # check current job finish?
        if current[2] > 0: # not finish
            time = current[1] + 1
            print("time up +1 ", time)

            next_idx = current[0] + 1
            print("next_idx", next_idx)
            # check start new?
            if next_idx < len(plans) and time >= plans[next_idx][1]:
                print("newt job start!")
                # start new
                pause.append(current)
                print("after add current job: pause: ", pause)

                current = [next_idx, plans[next_idx][1], plans[next_idx][2]]
                print("current update", current)

            # current = [idx, working time, left time]
            left_time = current.pop()
            working_time = current.pop() + 1
            print("current: left_time, working_time: ", left_time, working_time)

            # adjust time
            if working_time % 100 >= 60:
                working_time -= 60
                working_time += 100

            if working_time >= 2400:
                working_time -= 2400

            current.append(working_time)
            current.append(left_time - 1)
            print("update current!", current)

        else: # if finsish
            print("current is finish !", current)
            complete.append(current[0]) # only idx
            print("add complete!", complete)

            # check in pause
            if pause:
                current = pause.pop()
                print("puase has jobs: and current update!", pause, '->', current)

            else:
                print("there is no pause!")
                next_idx = current[0] + 1
                if next_idx < len(plans):
                    next_job = plans[next_idx]
                    current = [next_idx, next_job[1], next_job[2]]
                    print("next_job is set!", current)
                else:
                    print("there isn't another job, plans is empty")

        print("\n")

    print("logic finish! complete: ", complete)
    for c in complete:
        answer.append(plans[c][0])

    return answer
  • 코드가 너무 난잡하다
  • 시간 관리 로직이 복잡하다 -> 의도치 않게 변경될 수 있다.
  • branch가 너무 많아서 관리하기가 어렵다.

​

앞으로 이런 느낌으로 코드를 작성할거면, 다시 코드 작성을 고려하자.

더 간단하게 생각하기

with gpt\_o3

javascript 코드 예제
                                    🤔 시간 관리를 더 쉬우면서도 정확하게 하기
-> 모든 시간을 분으로 관리하자

🤔 조건을 명확하게 정하기 (이건 내가 정리한 로직)
- 1분씩 증가 x
- 시작시간은 처음 사용 이후 사용하지 않아도 된다.
- 체크사항:
>>> next job이 있는지?
>>> pause job이 있는지?
javascript 코드 예제
                                    def time_to_minute(time: str):
    hh, mm = map(int, time.split(":"))
    return hh * 60 + mm

def solution(plans):
    # plans의 각 요소: [name, start, playtime]
    # 시작 시각을 분 단위로 변환, playtime은 int
    for plan in plans:
        plan[1] = time_to_minute(plan[1])
        plan[2] = int(plan[2])

    # 시작 시각 오름차순 정렬
    plans.sort(key=lambda x: x[1])

    complete = []   # 완료된 과제의 이름을 순서대로 저장
    paused = []     # (과제 이름, 남은 시간)을 저장하는 스택 (LIFO)

    current_time = plans[0][1]
    # 현재 진행 중인 과제: (name, remaining_time)
    current_task = (plans[0][0], plans[0][2])
    i = 1  # 다음 과제의 인덱스

    while current_task is not None:
        # 다음 과제가 존재하는 경우
        if i < len(plans):
            next_start = plans[i][1]
            finish_time = current_time + current_task[1]
            # 만약 현재 과제를 finish하기 전에 다음 과제 시작 시각이 도래한다면
            if finish_time > next_start:
                # 현재 과제를 next_start까지 진행하고 중단
                dt = next_start - current_time  # 진행한 시간
                # 남은 시간 갱신
                current_task = (current_task[0], current_task[1] - dt)
                # 현재 시간 업데이트
                current_time = next_start
                # 진행 중이던 과제를 멈추고 스택에 저장
                paused.append(current_task)
                # 새 과제를 시작
                current_task = (plans[i][0], plans[i][2])
                i += 1
            else:
                # 현재 과제를 finish 할 수 있음 (finish_time <= next_start)
                current_time = finish_time
                complete.append(current_task[0])
                # 과제가 끝난 시각에 새 과제 시작 시간이 있다면
                # 문제 조건에 따라 새 과제를 우선 시작하므로, pause 스택은 그대로 둡니다.
                if i < len(plans) and current_time == plans[i][1]:
                    current_task = (plans[i][0], plans[i][2])
                    i += 1
                # 아니라면, 만약 멈춰둔 과제가 있다면 가장 최근에 멈춘 과제를 이어서 진행
                elif paused:
                    current_task = paused.pop()
                # paused에 과제가 없으면, 다음 과제가 있다면 그 과제를 시작
                elif i < len(plans):
                    # current_time을 다음 과제의 시작 시각으로 이동 (만약 current_time < next_start)
                    current_time = max(current_time, plans[i][1])
                    current_task = (plans[i][0], plans[i][2])
                    i += 1
                else:
                    current_task = None
        else:
            # 다음 과제가 없으면 현재 과제를 완료하고, 이어서 pause 스택에서 처리
            current_time += current_task[1]
            complete.append(current_task[0])
            if paused:
                current_task = paused.pop()
            else:
                current_task = None

    return complete
  • 구현이 너무 복잡해서 일단 복붙코드
  • 차후 다시 읽어보면서 공부해야 될 것 같다.

​

플랫폼 변경

이번 문제를 풀면서 꽤나 큰 좌절감을 느꼈다. 솔직히 이번에 느낀건 아직까지 lv2는 나한테 버겁다... 이번 년도 남은 준비기간이 6개월도 안된다. 매번 한다고하는데, 실력이 안는다. 공부시간을 더 투자해야할 것 같다.

​

찾아보닌깐 하루 1코테 하기에는 LeetCode가 좋다더라. 사실 나도 LeetCode할 때가 가장 좋긴했다. 무엇보다도 문제를 스스로 풀고 성장하고 있다고 느끼는게 공부를 지속하는데 큰 도움이된다. 근데 나는 아직까지 lc2를 정복하지도 못했다. 그냥 이제는 받아들이고 싶다. 나는 이정도 실력이구나...

​

그냥 LeetCode 쉬운 문제푸터 양치기 식으로 쭉 풀어나가야 겠다. 이런 쉬운 문제도 혼자 버거워 하는게 너무 마음이 안좋다.

​

다시보기

25.02.21 작성

문제를 풀고 다시 복기해보면서 정확한 논리를 정리하면 좋겠다는 생각이 들었다. 다시 제대로 정리해보자

javascript 코드 예제
                                    ✅ 1. 모든 시작 시간을 분으로 표시한다.

✅ 2. 모든 play_time을 int로 변경한다.

✅ 3. plasn를 시작 시간 기준으로 정렬한다.

✅ 여러 자료들
>>> current = (name, remain time)
>>> paused = current와 동일
>>> complete = name만 넣기
>>> time = 현재(전체) 시간을 관리하는 int값

🔑 논리

a. 다음 시작 시간이 존재한다.
1. 현재 시간 + 남은 시간 더한다.
>>> 1.1. 다음 시작 시간보다 크다.
>>> 1.2. 다음 시작 시간보다 작다.

1.1. 다음 시작 시간보다 크다.
>>> 현재 시간을 업데이트한다 = 다음 시작시간
>>> 현재 진행 중이던 job을 puased로 넘긴다. -> remain_time을 진행 시간 만큼 차감한다.
>>> 현재 job을 업데이트한다 = 다음 job

1.2. 다음 시작 시간보다 작다.
>>> 현재 일이 끝난 것으로 간주된다.
>>> 새로운 job으로 업데이트 해야한다.

1.2.1. 현재시간을 확인한다.
>>> 다음 시작시간보다 작다
>>>>> paused가 있는지 확인한다.
>>>>> 있으면 현재 job을 puased.pop()으로 업데이트
>>>>> 없으면 다음 job을 현재 job으로 update

b. 다음 시작시간이 존재하지 않는다.
1. 현재일 을 끝낸다.
2. puased를 확인한다
>>> 없다 -> 일이 끝난 것 -> current를 비워 줄 것
>>> 있다 -> pop해서 current로 계속 옮기기

810 / next = 840

마지막 코드 ...

javascript 코드 예제
                                    def time_to_minute(time: str):
    hh, mm = map(int, time.split(":"))
    return hh * 60 + mm

def solution(plans):
    complete = [] # name only

    for plan in plans:
        plan[1] = time_to_minute(plan[1])
        plan[2] = int(plan[2])

    plans.sort(key=lambda x: x[1])

    current = (plans[0][0], plans[0][2]) # name, remain
    time = plans[0][1] # start time = 1a minumum of plans start
    paused = [] # (name, remain)
    i = 1 # next point
    print("sorted:", plans)

    while current is not None:
        print(">>>\n")
        if i < len(plans): # do have next?
            print("i: ", i)
            print("exist next: \ntime:", time, "\ncurrent:", current, "\npaused: ", paused, "\nnext: [", plans[i][0], plans[i][2], "]")
            test_time = time + current[1]

            if test_time > plans[i][1]:
                paused.append((current[0], current[1] -(plans[i][1] - time)))
                current = (plans[i][0], plans[i][2])
                time = plans[i][1]
                i += 1
            else:
                # current finish
                complete.append(current[0])
                time = test_time

                if time == plans[i][1]:
                    current = (plans[i][0], plans[i][2])
                    i += 1
                else:
                    if paused:
                        current = paused.pop()
                    else:
                        current = (plans[i][0], plans[i][2])
                        i += 1

        else: # no have next
            print("not exist next", current, paused)
            # fininsh current
            complete.append(current[0])

            if paused:
                current = paused.pop()
            else:
                current = None
        print("\n<<<")

    return complete
  • current finish이후 paused가 없는 경우, 다음 작업이 남아있을 수 있다
  • 이를 체크하여 현재 작업을 다음 것으로 동기화 하였다.
  • 하지만, 현재 시간은 동기화 하지 않음.
  • 이를 동기화 시캬줘야 한다.
javascript 코드 예제
                                    🤔 상황
1. 현재 작업이 완료되었다.
2. paused에는 남은 작업이 없다.
3. 다음 작업이 존재한다.

그럼 현재 시간은 항상 = 다음시간으로 set하면된다.
javascript 코드 예제
                                    complete.append(current[0])
time = test_time

if i < len(plans) and time == plans[i][1]:
    current = (plans[i][0], plans[i][2])
    i += 1
elif paused:
    current = paused.pop()
elif i < len(plans):
    time = plans[i][1]
    current = (plans[i][0], plans[i][2])
    i += 1
else:
    current = None
  • 빡통 gpt가 계속 itme = max(time, plans\[i\]\[1\]로 알려줘서 한 30분 날렸다 ...