-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtask_scheduler.rs
150 lines (123 loc) · 4.04 KB
/
task_scheduler.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
use std::collections::BinaryHeap;
use std::collections::HashMap;
use std::collections::HashSet;
use std::collections::VecDeque;
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct Item {
count: usize,
letter: char,
}
impl Item {
pub fn new(letter: char) -> Self {
Self { count: 1, letter }
}
pub fn increment(&mut self) {
self.count += 1;
}
pub fn decrement(&mut self) {
if self.count > 0 {
self.count -= 1;
}
}
pub fn is_empty(&self) -> bool {
self.count == 0
}
}
/// Given a character array `tasks`, representing the tasks a CPU needs to do, where each letter
/// represents a different task. Tasks could be done in any order. Each task is done in one unit of
/// time, the CPU could complete either one task or just be idle.
///
/// However, there is a non-negative integer `n` that represents the cooldown period between the
/// two same tasks (the same letter in the array), that is that there must be at least `n` units of
/// time between any two same tasks.
///
/// Return the least number of units of times that the CPU will take to finish all the given tasks.
struct Solution;
impl Solution {
fn to_counts(tasks: Vec<char>) -> HashMap<char, Item> {
let mut results = HashMap::new();
for task in tasks {
results
.entry(task)
.and_modify(|item: &mut Item| item.increment())
.or_insert(Item::new(task));
}
results
}
fn to_heap(counts: HashMap<char, Item>) -> BinaryHeap<Item> {
let mut results = BinaryHeap::new();
for value in counts.values() {
results.push(*value);
}
results
}
// The actual solution is much simpler than this in that the slots can
// be prefilled by starting with the highest counts and scheduling them
// for the slot in the future when they'll next be able to be run.
pub fn least_interval(tasks: Vec<char>, n: i32) -> i32 {
let mut result = 0;
let n = n as usize;
let counts = Self::to_counts(tasks);
let mut heap = Self::to_heap(counts);
let mut queue: VecDeque<char> = VecDeque::new();
let mut current: HashSet<char> = HashSet::new();
while !heap.is_empty() {
result += 1;
if queue.len() == n+1 {
let first = queue.pop_front().unwrap();
if first != ' ' {
current.remove(&first);
}
}
let mut options: Vec<Item> = Vec::new();
let mut choice = ' ';
while !heap.is_empty() {
let mut option = heap.pop().unwrap();
if current.contains(&option.letter) {
options.push(option);
} else {
option.decrement();
choice = option.letter;
if !option.is_empty() {
options.push(option);
}
break;
}
}
queue.push_back(choice);
current.insert(choice);
for option in options {
heap.push(option);
}
}
result
}
}
#[cfg(test)]
mod tests {
use super::Solution;
#[test]
fn example_1() {
// [A, B, _, A, B, _, A, B]
let tasks = vec!['A', 'A', 'A', 'B', 'B', 'B'];
let n = 2;
let result = Solution::least_interval(tasks, n);
assert_eq!(result, 8);
}
#[test]
fn example_2() {
// [A, A, A, B, B, B]
let tasks = vec!['A', 'A', 'A', 'B', 'B', 'B'];
let n = 0;
let result = Solution::least_interval(tasks, n);
assert_eq!(result, 6);
}
#[test]
fn example_3() {
// [A, B, C, A, D, E, A, F, G, A, _, _, A, _, _, A]
let tasks = vec!['A','A','A','A','A','A','B','C','D','E','F','G'];
let n = 2;
let result = Solution::least_interval(tasks, n);
assert_eq!(result, 16);
}
}