High-Access Employees
Source: leetcode
Difficulty: Medium
Tags: array, hash-table, string, sorting

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 of **high\-access** employees with any order you want.*


 


**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 <= 100`
- `access_times[i].length == 2`
- `1 <= access_times[i][0].length <= 10`
- `access_times[i][0]` consists only of English small letters.
- `access_times[i][1].length == 4`
- `access_times[i][1]` is in 24\-hour time format.
- `access_times[i][1]` consists only of `'0'` to `'9'`.




C++ solution:
class Solution {
public:
    vector<string> findHighAccessEmployees(vector<vector<string>>& time) {
        int n=time.size();
        vector<string> ans;
        string flag;

        sort(time.begin(), time.end());
        for(int i=0; i<n-2; i++){
            if(flag!=time[i][0] && time[i][0]==time[i+2][0]){
               int a = stoi(time[i][1]);
               int b = stoi(time[i+2][1]);

               if(b-a<100){
                  flag=time[i][0];
                  ans.push_back(flag);
                  i++;
               }
            }
        }
        
        return ans;
    }
};

Go solution:
func findHighAccessEmployees(access_times [][]string) []string {
    sort.Slice(access_times,func(i,j int)bool{
        return access_times[i][1]<access_times[j][1]
    })  
    accessFreq:=map[string]int{}
    employees:=map[string]bool{}
    i,j:=0,0
    for i<len(access_times) && j<len(access_times){
        currTime,_:=strconv.Atoi(access_times[j][1])
        globalTime,_:=strconv.Atoi(access_times[i][1])
        for currTime<globalTime+100{
            accessFreq[access_times[j][0]]++ 
            if accessFreq[access_times[j][0]]>=3{
                employees[access_times[j][0]]=true
            } 
            j++  
            if j>=len(access_times){
                break
            }
            currTime,_=strconv.Atoi(access_times[j][1])
        }
        accessFreq[access_times[i][0]]--
        i++
    }
    ans:=[]string{}
    for key,_:=range employees{
        ans=append(ans,key)
    }
    return ans
}

Java solution:
public class Solution {
    // Function to find high-access employees based on access times.
    public List<String> findHighAccessEmployees(List<List<String>> access_times) {
        // Create a map to store access times for each employee.
        Map<String, List<Integer>> when = new HashMap<>();

        // Populate the map with access times from the input list.
        for (List<String> v : access_times) {
            String a = v.get(0), b = v.get(1);
            when.computeIfAbsent(a, k -> new ArrayList<>()).add(Integer.parseInt(b));
        }

        // List to store the names of high-access employees.
        List<String> ret = new ArrayList<>();

        // Iterate through the map to check access patterns for each employee.
        for (Map.Entry<String, List<Integer>> entry : when.entrySet()) {
            // Sort the access times for each employee.
            entry.getValue().sort(null);

            // Get the number of access times for the current employee.
            int k = entry.getValue().size();

            // Flag to indicate if the employee is a high-access employee.
            boolean flag = false;

            // Check for consecutive accesses within a 100-minute window.
            for (int i = 0; i + 3 <= k; ++i)
                flag |= entry.getValue().get(i + 2) < entry.getValue().get(i) + 100;

            // If the flag is true, the employee is considered high-access, and their name is added to the result.
            if (flag) ret.add(entry.getKey());
        }

        // Return the list containing the names of high-access employees.
        return ret;
    }
}

JavaScript solution:
/**
 * @param {string[][]} access_times
 * @return {string[]}
 */
var findHighAccessEmployees = function (at) {
    let count = {};
    for (let i = 0; i < at.length; i++) {
        if (!Number(at[i][1]) <= 5 || !Number(at[i][1]) >= 2350) {
            if (!count[at[i][0]]) {
                count[at[i][0]] = [Number(at[i][1])]
            } else {
                count[at[i][0]].push(Number(at[i][1]))
            }
        }

    }
    let res = [];
    for (let name in count) {
        let n = count[name].sort((a, b) => a - b)
        for (let i = 0; i < n.length; i++) {
            let num = 0;
            for (let j = i; j < n.length; j++) {
                if (Math.abs(n[i] - n[j]) < 100) {
                    num = num + 1;

                }
            }
            if (num >= 3) {
                res.push(name);
                break;
            }
        }
    }
    return res
};

Python solution:
class Solution:
    def findHighAccessEmployees(self, access_times: List[List[str]]) -> List[str]:
        mapping = defaultdict(list)
        for name, time in access_times:
            mapping[name].append(int(time))
        ans = []
        for name, times in mapping.items():
            times.sort()
            i = 0
            j = 1
            while i < len(times) and j < len(times):
                if times[j] - times[i] >= 100:
                    i += 1
                    j = i + 1
                elif j - i < 2:
                    j += 1
                else:
                    ans.append(name)
                    break
        return ans

Ruby solution:
def find_high_access_employees(access_times)
  employees = Hash.new { |h, k| h[k] = [] }
  access_times.each do |name, time|
    employees[name] << time.to_i
  end

  result = []
  employees.each do |name, times|
    next if times.size < 3

    sorted = times.sort
    (0..sorted.size - 3).each do |i|
      if sorted[i + 2] - sorted[i] < 100
        result << name
        break
      end
    end
  end

  result
end