这是一道非常综合的算法题,同时涉及到了哈希表、排序、滑动窗口。
先讲讲我的思路:
先将keyTime中每一项时刻的冒号都替换掉,变成数字字符串,再使用Hash Map来存每位员工的用卡时刻。遍历Hash Map中每位员工的时刻表(需要先按时间先后排序),判断是否有连续3个及以上的时刻都在一个小时内,具体到代码: 就是判断3个时刻中,当前项与后一项的差值总和不超过100(因为这里已经将时刻转换为了数字字符串,比如12:00和13:00之间相差60min,但转换过后对应的就是1300 - 1200 = 100),只要存在这样连续的3个时刻就立即结束循环,这个员工就是要找的那个员工。
下面附上源代码及注释:
//警告一小时内使用相同员工卡大于等于三次的人
function alertNames(keyName, keyTime) {
const hashMap = new Map();
// 通过将时间中的冒号替换为空字符串来去掉冒号
for (let j = 0; j < keyTime.length; ++j) {
keyTime[j] = keyTime[j].replace(':', '');
}
// 遍历keyName,使用Hash Map计数,统计每位员工的出入时刻
for (let i = 0; i < keyName.length; ++i) {
if (hashMap.has(keyName[i])) {
let cur = hashMap.get(keyName[i]);
cur.push(keyTime[i]);
hashMap.set(keyName[i], cur);
} else {
hashMap.set(keyName[i], [keyTime[i]]);
}
}
// 开辟一个数组,存放结果
const ansArr = new Array();
// 遍历hashMap,先对时刻进行排序
for (const [name, time] of hashMap) {
time.sort((a, b) => {
return a - b;
});
let count = 1;
let minutes = 100;
// 开始统计,使用minutes不断地减去后一个时刻与当前时刻的时差,count进行计数,根据时差的大小来收缩滑动窗口的左右边界
for (let key = 0; key < time.length - 1; ++key) {
if (time[key + 1] - time[key] <= minutes) {
count++;
minutes -= (time[key + 1] - time[key]);
} else {
// 收缩滑窗左边界再重新进行判断
if (time[key + 1] - time[key] <= 100) {
minutes = 100 - (time[key + 1] - time[key]);
count = 2;
} else {
minutes = 100;
count = 1;
}
}
// count >= 3,说明找到了这个员工,立即结束循环
if (count >= 3) {
ansArr.push(name);
break;
}
}
}
return ansArr.sort();
};
const staffName = ["leslie", "leslie", "leslie", "clare", "clare", "clare", "clare"], entryTime = ["13:00", "13:20", "14:00", "18:00", "18:51", "19:30", "19:49"];
console.log(alertNames(staffName, entryTime));