[LeetCode#621] Task Scheduler

2024. 9. 17. 22:25·Algorithm/문제풀이

 

❒ Description


날짜 2024.09.17 (화)
제목 Task Scheduler
링크 https://leetcode.com/problems/task-scheduler/description/
자료구조 배열 & 우선순위 큐
알고리즘 그리디
시간 복잡도 O(NlongN)

 

아이디어도 생각나지 않았던 문제였다.

 

 

 

 

 

❒ 문제 분석


이번 문제는 주어진 task를 모두 수행하기 위한 최소 횟수를 출력하는 것이다. 그리고 동일한 task를 수행하기 위해선

주어진 interval을 신경써줘야 한다. 문제에서 변수 `n`을 interval로 제시해준다.

 

예를 들어 interval이 3이라면 동일한 `A` 작업을 마무리하기 위해서는 `A _ _ _ A` 와 같이 3번의 interval이 필요

하다. 여기서 한 가지 규칙을 발견할 수 있다. 한 번의 cycle에서 총 `n + 1`개의 task를 처리할 수 있다는 규칙이다. 

여기서 한 번의 cycle이란 `A _ _`를 의미한다.

 

그리고 빈도수가 가장 많은 task 부터 처리하는 해야 문제의 목적인 최소 횟수 출력이라는 조건을 충족할 수 있다.

 

 

 

 

 

❒ Solution


1. 우선순위 큐

더보기
public int leastInterval(char[] tasks, int n) {
    int[] freqs = new int[26];
    for (char c : tasks) {
        freqs[c - 'A']++;
    }
    Queue<Integer> pq = new PriorityQueue<>((a, b) -> b - a);
    for (int freq : freqs) {
        if (freq > 0) {
            pq.add(freq);
        }
    }

    int result = 0;
    while (true) {
        int intervals = 0;
        List<Integer> pendingTasks = new ArrayList<>();
        while (!pq.isEmpty()) {
            int frequency = pq.poll();
            if (intervals < n + 1) {
                intervals ++;
                result ++;
                if (frequency > 1) {
                    pendingTasks.add(frequency - 1);
                }
            } else {
                pendingTasks.add(frequency);
            }
        }
        if (pendingTasks.isEmpty()) {
            break;
        }
        pq.addAll(pendingTasks);
        result += n + 1 - intervals;
    }
    return result;
}

i. Task 빈도 수 배열 생성

int freqs = new int[26];
for (char c : tasks) {
    freqs[c - 'A']++;
}
  • 주어진 task의 빈도를 계산한다. (freqs 배열)
  • 작업이 'A'라면 freqs[0]에, 'B'라면 freqs[1]에 저장한다.

 

ii ) 우선 순위 큐에 빈도가 1 이상인 값만 내림차순으로 삽입

Queue<Integer> pq = new PriorityQueue<>((a,b) -> b - a);
for (int freq : freqs) {
    pq.add(freq);
}

 

 

iii ) Main Logic - 하나의 cycle 동안에 작업 처리

int result = 0;
while (true) {
    int intervals = 0;
    
    // 다음 cycle에 처리할 task를 담을 ArrayList 선언
    List<Integer> pendingTasks = new ArrayList<>();
    
    // PQ가 빌 때 까지 반복
    while (!pq.isEmpty()) {
        int frequency = pq.poll():
    	if (intervals < n + 1) {
            intervals ++;
            results ++;
            if (frequency > 1) {
                pendingTasks.add(frequency - 1);
            }        
        } else {
            pendingTasks.add(frequency);
        }
    }
    
    // 다음 cycle에 작업할 task 없는 경우 while문 break
    if (pendingTasks.isEmpty()) {
        break;
    }
    
    // PQ에 다음 cycle에 처리할 task 삽입
    pq.addAll(pendingTasks);

    // cycle이 끝날 때 n + 1개의 작업이 다 채워지지 않았을 경우, 남은 interval을 추가한다. 
    result += n + 1 - intervals;
}
return result;

 

 

 

2.  최대 빈도 기반으로 idle 시간 계산

public int leastInterval(char[] tasks, int n) {
    int[] freqs = new int[26];
    for (char c : freqs) {
        freqs[c - 'A']++;
    }
    Arrays.sort(freqs);
    int maxFreq = freqs[25] - 1;
    int idle = maxFreq * n;
    for (int i = 24; i >= 0; i--) {
        idle -= Math.min(maxFreq, freqs[i]);
    }
    return idle > 0 ? idle + tasks.length : tasks.length;
}

두 번째 풀이는 최대 빈도 task 기준으로 풀이한 코드이다. 가장 빈도가 높은 작업의 빈도에서 1을 뺀 값을 기반으로

나머지 작업이 얼마나 채워질 수 있는지 계산한다. 

 

 

3. 공식 사용...? 

public int leastInterval(char[] tasks, int n) {
    int[] freqs = new int[26];
    for(char c: tasks) {
        freqs[c - 'A']++;    
    }

    int maxFreq = 0;
    int maxCount = 0;
    for(int freq : freqs) {
        if(freq > maxFreq) {
            maxFreq = freq;
            maxCount = 1;
        }
        else if(freq == maxFreq) {
            maxCount++;
        }
    }
    int minIntervals = (maxFreq-1) * (n+1) + maxCount;
    return Math.max(minIntervals, tasks.length);
}

이 풀이는 최소 간격을 구하는 공식을 사용한 풀이로 보인다.

※ 공식 : (maxFreq - 1) x (n + 1) + maxCount 

 

 

 

 

 

 


 

'Algorithm > 문제풀이' 카테고리의 다른 글

[LeetCode#455] Assign Cookies  (0) 2024.09.19
[LeetCode#134] Gas Station  (0) 2024.09.18
[LeetCode#406] Queue reconstruction by height  (0) 2024.09.17
[LeetCode#122] Best Time to Buy and Sell II  (0) 2024.09.16
[LeetCode#55] Jump Game  (0) 2024.09.16
'Algorithm/문제풀이' 카테고리의 다른 글
  • [LeetCode#455] Assign Cookies
  • [LeetCode#134] Gas Station
  • [LeetCode#406] Queue reconstruction by height
  • [LeetCode#122] Best Time to Buy and Sell II
gilbert9172
gilbert9172
gilbert9172 님의 블로그 입니다.
  • gilbert9172
    バックエンド
    gilbert9172
  • 전체
    오늘
    어제
    • All Categories (175)
      • 우테코 7기 (21)
        • 1주차 (8)
        • 2주차 (5)
        • 3주차 (6)
      • Langauge (4)
        • Java (3)
        • Kotlin (1)
      • Back-End (13)
        • SpringBoot (1)
        • Trouble Shooting (0)
        • Setup & Configuration (1)
        • SQL (3)
        • Redis (8)
      • Architecture (6)
        • Multi Module (1)
        • DDD (5)
      • CS (30)
        • Data Structure (6)
        • Operating System (0)
        • Network (12)
        • Database (10)
        • Design Pattern (2)
      • Algorithm (78)
        • 내용 정리 (18)
        • 문제풀이 (60)
      • DevOps (6)
        • AWS (5)
        • Git (1)
      • Front-End (1)
        • Trouble Shooting (1)
      • Project (6)
        • 페이스콕 (6)
      • Book (9)
        • 이벤트 기반 마이크로서비스 구축 (7)
        • 친절한 SQL 튜닝 (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    binarysearch
    sliding-window
    Two-Pointer
    Back-Tracking
    부분단조성
    오블완
    greedy
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.2
gilbert9172
[LeetCode#621] Task Scheduler
상단으로

티스토리툴바