High-Access Employees
Problem
You are given a 2D 0-indexed array of strings, access_times, with size n. For each i where 0 <= i <= n - 1, access_times[i][0] represents the name of an employee, and access_times[i][1] represents the access time of that employee. All entries in access_times are within the same day.
The access time is represented as four digits using a 24-hour time format, for example, "0800" or "2250".
An employee is said to be high-access if he has accessed the system three or more times within a one-hour period.
Times with exactly one hour of difference are not considered part of the same one-hour period. For example, "0815" and "0915" are not part of the same one-hour period.
Access times at the start and end of the day are not counted within the same one-hour period. For example, "0005" and "2350" are not part of the same one-hour period.
Return a list that contains the names ofhigh-access employees with any order you want.
Examples
Example 1
Input: access_times = [["a","0549"],["b","0457"],["a","0532"],["a","0621"],["b","0540"]]
Output: ["a"]
Explanation: "a" has three access times in the one-hour period of [05:32, 06:31] which are 05:32, 05:49, and 06:21.
But "b" does not have more than two access times at all.
So the answer is ["a"].
Example 2
Input: access_times = [["d","0002"],["c","0808"],["c","0829"],["e","0215"],["d","1508"],["d","1444"],["d","1410"],["c","0809"]]
Output: ["c","d"]
Explanation: "c" has three access times in the one-hour period of [08:08, 09:07] which are 08:08, 08:09, and 08:29.
"d" has also three access times in the one-hour period of [14:10, 15:09] which are 14:10, 14:44, and 15:08.
However, "e" has just one access time, so it can not be in the answer and the final answer is ["c","d"].
Example 3
Input: access_times = [["cd","1025"],["ab","1025"],["cd","1046"],["cd","1055"],["ab","1124"],["ab","1120"]]
Output: ["ab","cd"]
Explanation: "ab" has three access times in the one-hour period of [10:25, 11:24] which are 10:25, 11:20, and 11:24.
"cd" has also three access times in the one-hour period of [10:25, 11:24] which are 10:25, 10:46, and 10:55.
So the answer is ["ab","cd"].
Constraints
1 <= access_times.length <= 100access_times[i].length == 21 <= access_times[i][0].length <= 10access_times[i][0]consists only of English small letters.access_times[i][1].length == 4access_times[i][1]is in 24-hour time format.access_times[i][1]consists only of'0'to'9'.
Solution
Method 1 – Sliding Window with Sorting
Intuition
If we sort each employee's access times, we can efficiently check for any three accesses within a one-hour window using a sliding window approach. This works because the times are in a fixed format and can be compared as integers.
Approach
- Group all access times by employee name.
- Convert each time string (e.g., "0549") to minutes since midnight for easy comparison.
- For each employee, sort their access times.
- Use a sliding window of size 3 to check if the difference between the earliest and latest in the window is less than 60 minutes.
- If such a window exists, add the employee to the answer list.
- Return the list of high-access employees.
Code
C++
class Solution {
public:
vector<string> findHighAccessEmployees(vector<vector<string>>& access_times) {
unordered_map<string, vector<int>> m;
for (auto& x : access_times) {
int t = stoi(x[1].substr(0,2)) * 60 + stoi(x[1].substr(2,2));
m[x[0]].push_back(t);
}
vector<string> ans;
for (auto& [name, times] : m) {
sort(times.begin(), times.end());
for (int i = 2; i < times.size(); ++i) {
if (times[i] - times[i-2] < 60) {
ans.push_back(name);
break;
}
}
}
return ans;
}
};
Go
func findHighAccessEmployees(accessTimes [][]string) []string {
m := map[string][]int{}
for _, x := range accessTimes {
h := (int(x[1][0]-'0')*10 + int(x[1][1]-'0')) * 60
min := int(x[1][2]-'0')*10 + int(x[1][3]-'0')
t := h + min
m[x[0]] = append(m[x[0]], t)
}
ans := []string{}
for name, times := range m {
sort.Ints(times)
for i := 2; i < len(times); i++ {
if times[i]-times[i-2] < 60 {
ans = append(ans, name)
break
}
}
}
return ans
}
Java
class Solution {
public List<String> findHighAccessEmployees(List<List<String>> accessTimes) {
Map<String, List<Integer>> m = new HashMap<>();
for (List<String> x : accessTimes) {
int t = Integer.parseInt(x.get(1).substring(0,2)) * 60 + Integer.parseInt(x.get(1).substring(2,2));
m.computeIfAbsent(x.get(0), k -> new ArrayList<>()).add(t);
}
List<String> ans = new ArrayList<>();
for (var e : m.entrySet()) {
List<Integer> times = e.getValue();
Collections.sort(times);
for (int i = 2; i < times.size(); ++i) {
if (times.get(i) - times.get(i-2) < 60) {
ans.add(e.getKey());
break;
}
}
}
return ans;
}
}
Kotlin
class Solution {
fun findHighAccessEmployees(accessTimes: List<List<String>>): List<String> {
val m = mutableMapOf<String, MutableList<Int>>()
for (x in accessTimes) {
val t = x[1].substring(0,2).toInt() * 60 + x[1].substring(2,4).toInt()
m.getOrPut(x[0]) { mutableListOf() }.add(t)
}
val ans = mutableListOf<String>()
for ((name, times) in m) {
times.sort()
for (i in 2 until times.size) {
if (times[i] - times[i-2] < 60) {
ans.add(name)
break
}
}
}
return ans
}
}
Python
class Solution:
def findHighAccessEmployees(self, access_times: list[list[str]]) -> list[str]:
m: dict[str, list[int]] = {}
for name, t in access_times:
mins = int(t[:2]) * 60 + int(t[2:])
m.setdefault(name, []).append(mins)
ans: list[str] = []
for name, times in m.items():
times.sort()
for i in range(2, len(times)):
if times[i] - times[i-2] < 60:
ans.append(name)
break
return ans
Rust
impl Solution {
pub fn find_high_access_employees(access_times: Vec<Vec<String>>) -> Vec<String> {
use std::collections::HashMap;
let mut m: HashMap<String, Vec<i32>> = HashMap::new();
for x in &access_times {
let t = x[1][..2].parse::<i32>().unwrap() * 60 + x[1][2..].parse::<i32>().unwrap();
m.entry(x[0].clone()).or_default().push(t);
}
let mut ans = vec![];
for (name, times) in m.iter_mut() {
times.sort();
for i in 2..times.len() {
if times[i] - times[i-2] < 60 {
ans.push(name.clone());
break;
}
}
}
ans
}
}
TypeScript
class Solution {
findHighAccessEmployees(accessTimes: string[][]): string[] {
const m: Record<string, number[]> = {};
for (const [name, t] of accessTimes) {
const mins = parseInt(t.slice(0,2)) * 60 + parseInt(t.slice(2));
if (!m[name]) m[name] = [];
m[name].push(mins);
}
const ans: string[] = [];
for (const name in m) {
m[name].sort((a, b) => a - b);
for (let i = 2; i < m[name].length; ++i) {
if (m[name][i] - m[name][i-2] < 60) {
ans.push(name);
break;
}
}
}
return ans;
}
}
Complexity
- ⏰ Time complexity:
O(n log n)per employee, where n is the number of access times for that employee, due to sorting. Overall, O(N log K), where N is total records and K is max accesses per employee. - 🧺 Space complexity:
O(N), for storing all access times grouped by employee.