【2024年华为OD机试】 (C卷,100分)- 考勤信息(JavaScriptJava PythonC/C++)
一、问题描述
公司用一个字符串来表示员工的出勤信息,具体包括以下几种状态:
- absent:缺勤
- late:迟到
- leaveearly:早退
- present:正常上班
现需根据员工出勤信息,判断本次是否能获得出勤奖。获得出勤奖的条件如下:
- 缺勤不超过一次;
- 没有连续的迟到/早退;
- 任意连续7次考勤,缺勤/迟到/早退不超过3次。
输入描述
- 用户的考勤数据字符串。
- 记录条数 >= 1;
- 输入字符串长度 < 10000;
- 不存在非法输入。
示例输入
2
present
present absent present present leaveearly present absent
输出描述
根据考勤数据字符串,如果能得到出勤奖,输出 "true"
;否则输出 "false"
。
示例输出
true
false
题目解析
1. 出勤奖条件分析
条件1:缺勤不超过一次
- 统计整个考勤记录中
absent
的次数。 - 如果
absent
的次数 > 1,则不满足条件。
条件2:没有连续的迟到/早退
- 遍历考勤记录,检查是否存在连续的
late
或leaveearly
。 - 如果存在连续的
late
或leaveearly
,则不满足条件。
条件3:任意连续7次考勤,缺勤/迟到/早退不超过3次
- 使用滑动窗口统计任意连续7次考勤中
absent
、late
、leaveearly
的总次数。 - 如果任意窗口内这些状态的总次数 > 3,则不满足条件。
2. 滑动窗口的应用
滑动窗口是解决此类问题的有效方法。具体步骤如下:
-
窗口定义:
- 窗口长度为7。
- 当窗口右边界索引
R < 7
时,窗口长度为R + 1
。 - 当窗口右边界索引
R >= 7
时,窗口长度为7,左边界索引L = R - 6
。
-
统计窗口内的状态:
- 统计窗口内
present
的次数。 - 通过窗口长度减去
present
的次数,得到absent
、late
、leaveearly
的总次数。
- 统计窗口内
-
判断条件:
- 如果窗口内
absent
、late
、leaveearly
的总次数 > 3,则不满足条件。
- 如果窗口内
3. 解题思路
-
遍历考勤记录:
- 统计
absent
的总次数,判断是否超过1次。 - 检查是否存在连续的
late
或leaveearly
。
- 统计
-
滑动窗口统计:
- 使用滑动窗口统计任意连续7次考勤中
absent
、late
、leaveearly
的总次数。 - 如果任意窗口内这些状态的总次数 > 3,则不满足条件。
- 使用滑动窗口统计任意连续7次考勤中
-
综合判断:
- 如果所有条件均满足,则输出
"true"
;否则输出"false"
。
- 如果所有条件均满足,则输出
4. 示例解析
示例1
输入:
2
present
present present
输出:
true
true
解析:
- 第一个记录:只有
present
,满足所有条件。 - 第二个记录:只有
present
,满足所有条件。
示例2
输入:
2
present
present absent present present leaveearly present absent
输出:
true
false
解析:
- 第一个记录:只有
present
,满足所有条件。 - 第二个记录:
absent
出现2次,不满足条件1。- 存在
leaveearly
和absent
,但未连续,满足条件2。 - 滑动窗口检查发现某些窗口内
absent
、late
、leaveearly
的总次数 > 3,不满足条件3。
5. 总结
本题的核心在于:
- 条件1:统计
absent
的总次数。 - 条件2:检查是否存在连续的
late
或leaveearly
。 - 条件3:使用滑动窗口统计任意连续7次考勤中
absent
、late
、leaveearly
的总次数。
通过合理设计滑动窗口和遍历逻辑,可以高效解决此类问题。
二、JavaScript算法源码
以下是代码的详细注释和讲解,帮助理解每一部分的逻辑和实现。
代码结构
- 主函数:
- 读取输入数据并解析。
- 调用
getResult
函数处理每条考勤记录。
getResult
函数:- 遍历每条考勤记录,调用
isAward
函数判断是否能获得出勤奖。
- 遍历每条考勤记录,调用
isAward
函数:- 核心逻辑,判断单条考勤记录是否满足出勤奖的条件。
代码逐行注释
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;
void (async function () {
// 读取输入的记录条数
const n = parseInt(await readline());
const records = [];
// 读取每条考勤记录并存入数组
for (let i = 0; i < n; i++) {
records.push((await readline()).split(" "));
}
// 调用 getResult 函数处理所有记录
getResult(records);
})();
function getResult(records) {
// 遍历每条考勤记录,调用 isAward 函数判断是否能获得出勤奖
for (let record of records) console.log(isAward(record));
}
function isAward(record) {
// 总缺勤次数
let absent = 0;
// 滑窗内正常上班的次数
let present = 0;
// 记录前一次的考勤记录
let preRecord = "";
// 遍历考勤记录
for (let i = 0; i < record.length; i++) {
// 滑窗长度最大为7,如果超过7,则滑窗的左边界需要右移
// 滑窗失去的部分是 record[i - 7]
// 如果失去部分是 present,则更新滑窗内 present 次数
if (i >= 7) {
if ("present" == record[i - 7]) present--;
}
// 当前的考勤记录
const curRecord = record[i];
// 根据当前考勤记录的类型进行处理
switch (curRecord) {
case "absent":
// 缺勤不超过一次
if (++absent > 1) return false;
break;
case "late":
case "leaveearly":
// 没有连续的迟到/早退
if ("late" == preRecord || "leaveearly" == preRecord) return false;
break;
case "present":
// 正常上班,滑窗内 present 次数加1
present++;
break;
}
// 更新前一次的考勤记录
preRecord = curRecord;
// 任意连续7次考勤,缺勤/迟到/早退不超过3次
// 相当于判断:滑窗长度 - present次数 <= 3
const window_len = Math.min(i + 1, 7);
if (window_len - present > 3) return false;
}
// 如果所有条件都满足,返回 true
return true;
}
代码逻辑详解
1. 主函数
rl
:创建一个readline
接口,用于读取用户输入。iter
:获取异步迭代器,用于逐行读取输入。readline
函数:异步读取一行输入。void (async function () { ... })();
:- 立即执行一个异步函数,读取输入数据并解析。
- 读取记录条数
n
。 - 读取每条考勤记录并存入
records
数组。 - 调用
getResult
函数处理所有记录。
2. getResult
函数
- 功能:遍历每条考勤记录,调用
isAward
函数判断是否能获得出勤奖。 for (let record of records)
:- 遍历
records
数组中的每条考勤记录。 - 调用
isAward
函数判断当前记录是否满足条件。 - 输出结果(
true
或false
)。
- 遍历
3. isAward
函数
- 功能:判断单条考勤记录是否满足出勤奖的条件。
- 变量说明:
absent
:统计缺勤次数。present
:统计滑窗内正常上班的次数。preRecord
:记录前一次的考勤记录,用于判断是否有连续的迟到/早退。
- 遍历考勤记录:
- 滑窗逻辑:
- 滑窗长度最大为7。
- 如果当前索引
i >= 7
,则滑窗左边界右移,失去的部分是record[i - 7]
。 - 如果失去的部分是
present
,则滑窗内present
次数减1。
- 当前考勤记录处理:
absent
:- 缺勤次数加1。
- 如果缺勤次数 > 1,返回
false
。
late
或leaveearly
:- 检查前一次考勤记录是否是
late
或leaveearly
。 - 如果是,则存在连续的迟到/早退,返回
false
。
- 检查前一次考勤记录是否是
present
:- 滑窗内
present
次数加1。
- 滑窗内
- 更新前一次考勤记录:
- 将当前考勤记录赋值给
preRecord
。
- 将当前考勤记录赋值给
- 滑窗内缺勤/迟到/早退次数检查:
- 计算滑窗长度
window_len
(当前索引 + 1,最大为7)。 - 如果滑窗长度减去
present
次数 > 3,返回false
。
- 计算滑窗长度
- 滑窗逻辑:
- 返回结果:
- 如果所有条件都满足,返回
true
。
- 如果所有条件都满足,返回
示例运行
输入:
2
present
present absent present present leaveearly present absent
输出:
true
false
解析:
- 第一条记录:
- 只有
present
,满足所有条件,输出true
。
- 只有
- 第二条记录:
absent
出现2次,不满足条件1。- 存在
leaveearly
和absent
,但未连续,满足条件2。 - 滑动窗口检查发现某些窗口内
absent
、late
、leaveearly
的总次数 > 3,不满足条件3。 - 输出
false
。
总结
- 代码通过遍历考勤记录,结合滑动窗口和状态统计,高效判断是否满足出勤奖的条件。
- 核心逻辑集中在
isAward
函数中,通过滑窗和状态检查实现条件判断。
三、Java算法源码
以下是 Java 代码的详细注释和讲解,帮助理解每一部分的逻辑和实现。
代码结构
- 主函数
main
:- 读取输入数据并解析。
- 调用
getResult
函数处理每条考勤记录。
getResult
函数:- 遍历每条考勤记录,调用
isAward
函数判断是否能获得出勤奖。
- 遍历每条考勤记录,调用
isAward
函数:- 核心逻辑,判断单条考勤记录是否满足出勤奖的条件。
代码逐行注释
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// 读取输入的记录条数
int n = Integer.parseInt(sc.nextLine());
// 初始化考勤记录数组
String[][] records = new String[n][];
for (int i = 0; i < n; i++) {
// 读取每条考勤记录并拆分为数组
records[i] = sc.nextLine().split(" ");
}
// 调用 getResult 函数处理所有记录
getResult(n, records);
}
public static void getResult(int n, String[][] records) {
// 遍历每条考勤记录,调用 isAward 函数判断是否能获得出勤奖
for (int i = 0; i < n; i++) {
System.out.println(isAward(records[i]));
}
}
public static boolean isAward(String[] record) {
// 总缺勤次数
int absent = 0;
// 滑窗内正常上班的次数
int present = 0;
// 记录前一次的考勤记录
String preRecord = "";
// 遍历考勤记录
for (int i = 0; i < record.length; i++) {
// 滑窗长度最大为7,如果超过7,则滑窗的左边界需要右移
// 滑窗失去的部分是 record[i - 7]
// 如果失去部分是 present,则更新滑窗内 present 次数
if (i >= 7) {
if ("present".equals(record[i - 7])) present--;
}
// 当前的考勤记录
String curRecord = record[i];
// 根据当前考勤记录的类型进行处理
switch (curRecord) {
case "absent":
// 缺勤不超过一次
if (++absent > 1) return false;
break;
case "late":
case "leaveearly":
// 没有连续的迟到/早退
if ("late".equals(preRecord) || "leaveearly".equals(preRecord)) return false;
break;
case "present":
// 正常上班,滑窗内 present 次数加1
present++;
break;
}
// 更新前一次的考勤记录
preRecord = curRecord;
// 任意连续7次考勤,缺勤/迟到/早退不超过3次
// 相当于判断:滑窗长度 - present次数 <= 3
int window_len = Math.min(i + 1, 7); // 滑窗长度
if (window_len - present > 3) return false;
}
// 如果所有条件都满足,返回 true
return true;
}
}
代码逻辑详解
1. 主函数 main
Scanner sc = new Scanner(System.in);
:- 创建一个
Scanner
对象,用于读取用户输入。
- 创建一个
int n = Integer.parseInt(sc.nextLine());
:- 读取记录条数
n
。
- 读取记录条数
String[][] records = new String[n][];
:- 初始化一个二维数组
records
,用于存储每条考勤记录。
- 初始化一个二维数组
for (int i = 0; i < n; i++) { ... }
:- 读取每条考勤记录并拆分为数组,存入
records
中。
- 读取每条考勤记录并拆分为数组,存入
getResult(n, records);
:- 调用
getResult
函数处理所有记录。
- 调用
2. getResult
函数
- 功能:遍历每条考勤记录,调用
isAward
函数判断是否能获得出勤奖。 for (int i = 0; i < n; i++) { ... }
:- 遍历
records
数组中的每条考勤记录。 - 调用
isAward
函数判断当前记录是否满足条件。 - 输出结果(
true
或false
)。
- 遍历
3. isAward
函数
- 功能:判断单条考勤记录是否满足出勤奖的条件。
- 变量说明:
absent
:统计缺勤次数。present
:统计滑窗内正常上班的次数。preRecord
:记录前一次的考勤记录,用于判断是否有连续的迟到/早退。
- 遍历考勤记录:
- 滑窗逻辑:
- 滑窗长度最大为7。
- 如果当前索引
i >= 7
,则滑窗左边界右移,失去的部分是record[i - 7]
。 - 如果失去的部分是
present
,则滑窗内present
次数减1。
- 当前考勤记录处理:
absent
:- 缺勤次数加1。
- 如果缺勤次数 > 1,返回
false
。
late
或leaveearly
:- 检查前一次考勤记录是否是
late
或leaveearly
。 - 如果是,则存在连续的迟到/早退,返回
false
。
- 检查前一次考勤记录是否是
present
:- 滑窗内
present
次数加1。
- 滑窗内
- 更新前一次考勤记录:
- 将当前考勤记录赋值给
preRecord
。
- 将当前考勤记录赋值给
- 滑窗内缺勤/迟到/早退次数检查:
- 计算滑窗长度
window_len
(当前索引 + 1,最大为7)。 - 如果滑窗长度减去
present
次数 > 3,返回false
。
- 计算滑窗长度
- 滑窗逻辑:
- 返回结果:
- 如果所有条件都满足,返回
true
。
- 如果所有条件都满足,返回
示例运行
输入:
2
present
present absent present present leaveearly present absent
输出:
true
false
解析:
- 第一条记录:
- 只有
present
,满足所有条件,输出true
。
- 只有
- 第二条记录:
absent
出现2次,不满足条件1。- 存在
leaveearly
和absent
,但未连续,满足条件2。 - 滑动窗口检查发现某些窗口内
absent
、late
、leaveearly
的总次数 > 3,不满足条件3。 - 输出
false
。
总结
- 代码通过遍历考勤记录,结合滑动窗口和状态统计,高效判断是否满足出勤奖的条件。
- 核心逻辑集中在
isAward
函数中,通过滑窗和状态检查实现条件判断。
四、Python算法源码
以下是 Python 代码的详细注释和讲解,帮助理解每一部分的逻辑和实现。
代码结构
- 输入获取:
- 读取输入的记录条数
n
。 - 读取每条考勤记录并拆分为列表,存入
records
中。
- 读取输入的记录条数
isAward
函数:- 核心逻辑,判断单条考勤记录是否满足出勤奖的条件。
getResult
函数:- 遍历每条考勤记录,调用
isAward
函数判断是否能获得出勤奖。
- 遍历每条考勤记录,调用
- 算法调用:
- 调用
getResult
函数处理所有记录。
- 调用
代码逐行注释
# 输入获取
n = int(input()) # 读取记录条数
records = [input().split() for _ in range(n)] # 读取每条考勤记录并拆分为列表
def isAward(record):
# 总缺勤次数
absent = 0
# 滑窗内正常上班的次数
present = 0
# 定义迟到和早退的元组,用于判断连续的迟到/早退
late_leaveearly = ("late", "leaveearly")
# 前一次的考勤记录
preRecord = ""
# 遍历考勤记录
for i in range(len(record)):
# 滑窗长度最大为7,如果超过7,则滑窗的左边界需要右移
# 滑窗失去的部分是 record[i - 7]
# 如果失去部分是 present,则更新滑窗内 present 次数
if i >= 7:
if "present" == record[i - 7]:
present -= 1
# 当前的考勤记录
curRecord = record[i]
# 根据当前考勤记录的类型进行处理
if "absent" == curRecord:
absent += 1
# 缺勤超过1次,则拿不到全勤奖
if absent > 1:
return "false"
elif curRecord in late_leaveearly and preRecord in late_leaveearly:
# 连续的迟到/早退,则拿不到全勤奖
return "false"
elif "present" == curRecord:
# 正常上班,滑窗内 present 次数加1
present += 1
# 更新前一次的考勤记录
preRecord = curRecord
# 任意连续7次考勤,缺勤/迟到/早退不超过3次
# 相当于判断:滑窗长度 - present次数 <= 3
window_len = min(i + 1, 7) # 滑窗长度
if window_len - present > 3:
return "false"
# 如果所有条件都满足,返回 true
return "true"
# 算法入口
def getResult():
# 遍历每条考勤记录,调用 isAward 函数判断是否能获得出勤奖
for record in records:
print(isAward(record))
# 算法调用
getResult()
代码逻辑详解
1. 输入获取
n = int(input())
:- 读取记录条数
n
。
- 读取记录条数
records = [input().split() for _ in range(n)]
:- 读取每条考勤记录并拆分为列表,存入
records
中。
- 读取每条考勤记录并拆分为列表,存入
2. isAward
函数
- 功能:判断单条考勤记录是否满足出勤奖的条件。
- 变量说明:
absent
:统计缺勤次数。present
:统计滑窗内正常上班的次数。late_leaveearly
:定义迟到和早退的元组,用于判断连续的迟到/早退。preRecord
:记录前一次的考勤记录,用于判断是否有连续的迟到/早退。
- 遍历考勤记录:
- 滑窗逻辑:
- 滑窗长度最大为7。
- 如果当前索引
i >= 7
,则滑窗左边界右移,失去的部分是record[i - 7]
。 - 如果失去的部分是
present
,则滑窗内present
次数减1。
- 当前考勤记录处理:
absent
:- 缺勤次数加1。
- 如果缺勤次数 > 1,返回
false
。
late
或leaveearly
:- 检查前一次考勤记录是否是
late
或leaveearly
。 - 如果是,则存在连续的迟到/早退,返回
false
。
- 检查前一次考勤记录是否是
present
:- 滑窗内
present
次数加1。
- 滑窗内
- 更新前一次考勤记录:
- 将当前考勤记录赋值给
preRecord
。
- 将当前考勤记录赋值给
- 滑窗内缺勤/迟到/早退次数检查:
- 计算滑窗长度
window_len
(当前索引 + 1,最大为7)。 - 如果滑窗长度减去
present
次数 > 3,返回false
。
- 计算滑窗长度
- 滑窗逻辑:
- 返回结果:
- 如果所有条件都满足,返回
true
。
- 如果所有条件都满足,返回
3. getResult
函数
- 功能:遍历每条考勤记录,调用
isAward
函数判断是否能获得出勤奖。 for record in records:
:- 遍历
records
列表中的每条考勤记录。 - 调用
isAward
函数判断当前记录是否满足条件。 - 输出结果(
true
或false
)。
- 遍历
4. 算法调用
getResult()
:- 调用
getResult
函数处理所有记录。
- 调用
示例运行
输入:
2
present
present absent present present leaveearly present absent
输出:
true
false
解析:
- 第一条记录:
- 只有
present
,满足所有条件,输出true
。
- 只有
- 第二条记录:
absent
出现2次,不满足条件1。- 存在
leaveearly
和absent
,但未连续,满足条件2。 - 滑动窗口检查发现某些窗口内
absent
、late
、leaveearly
的总次数 > 3,不满足条件3。 - 输出
false
。
总结
- 代码通过遍历考勤记录,结合滑动窗口和状态统计,高效判断是否满足出勤奖的条件。
- 核心逻辑集中在
isAward
函数中,通过滑窗和状态检查实现条件判断。
五、C/C++算法源码:
以下是 C++ 和 C语言 版本的代码实现,并附带详细的中文注释和讲解。
C++ 版本
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// 判断两个字符串是否相等
bool eq(const string& a, const string& b) {
return a == b;
}
// 判断单条考勤记录是否满足出勤奖条件
bool isAward(const vector<string>& records) {
// 总缺勤次数
int absent = 0;
// 滑窗内正常上班的次数
int present = 0;
// 记录前一次的考勤记录
string preRecord = "";
for (int i = 0; i < records.size(); i++) {
// 滑窗长度最大为7,如果超过7,则滑窗的左边界需要右移
// 滑窗失去的部分是 records[i - 7]
// 如果失去部分是 present,则更新滑窗内 present 次数
if (i >= 7) {
if (eq("present", records[i - 7])) present--;
}
// 当前的考勤记录
string curRecord = records[i];
if (eq(curRecord, "absent")) {
// 缺勤不超过一次
if (++absent > 1) return false;
} else if (eq(curRecord, "late") || eq(curRecord, "leaveearly")) {
// 没有连续的迟到/早退
if (eq(preRecord, "late") || eq(preRecord, "leaveearly")) return false;
} else if (eq(curRecord, "present")) {
// 正常上班,滑窗内 present 次数加1
present++;
}
// 更新前一次的考勤记录
preRecord = curRecord;
// 任意连续7次考勤,缺勤/迟到/早退不超过3次
// 相当于判断:滑窗长度 - present次数 <= 3
int window_len = min(i + 1, 7);
if (window_len - present > 3) return false;
}
// 如果所有条件都满足,返回 true
return true;
}
int main() {
int n;
cin >> n; // 读取记录条数
cin.ignore(); // 忽略换行符
for (int i = 0; i < n; i++) {
string line;
getline(cin, line); // 读取一行考勤记录
vector<string> records;
string record;
for (char ch : line) {
if (ch == ' ') {
records.push_back(record);
record.clear();
} else {
record += ch;
}
}
if (!record.empty()) records.push_back(record);
// 调用 isAward 函数判断是否能获得出勤奖
cout << (isAward(records) ? "true" : "false") << endl;
}
return 0;
}
C语言版本
#include <stdio.h>
#include <string.h>
#define MIN(a, b) ((a) < (b) ? (a) : (b))
// 判断两个字符串是否相等
int eq(const char* a, const char* b) {
return strcmp(a, b) == 0;
}
// 判断单条考勤记录是否满足出勤奖条件
int isAward(char records[][15], int records_size) {
// 总缺勤次数
int absent = 0;
// 滑窗内正常上班的次数
int present = 0;
// 记录前一次的考勤记录
const char* preRecord = "";
for (int i = 0; i < records_size; i++) {
// 滑窗长度最大为7,如果超过7,则滑窗的左边界需要右移
// 滑窗失去的部分是 records[i - 7]
// 如果失去部分是 present,则更新滑窗内 present 次数
if (i >= 7) {
if (eq("present", records[i - 7])) present--;
}
// 当前的考勤记录
const char* curRecord = records[i];
if (eq(curRecord, "absent")) {
// 缺勤不超过一次
if (++absent > 1) return 0;
} else if (eq(curRecord, "late") || eq(curRecord, "leaveearly")) {
// 没有连续的迟到/早退
if (eq(preRecord, "late") || eq(preRecord, "leaveearly")) return 0;
} else if (eq(curRecord, "present")) {
// 正常上班,滑窗内 present 次数加1
present++;
}
// 更新前一次的考勤记录
preRecord = curRecord;
// 任意连续7次考勤,缺勤/迟到/早退不超过3次
// 相当于判断:滑窗长度 - present次数 <= 3
int window_len = MIN(i + 1, 7);
if (window_len - present > 3) return 0;
}
// 如果所有条件都满足,返回 true
return 1;
}
int main() {
int n;
scanf("%d", &n); // 读取记录条数
getchar(); // 忽略换行符
for (int i = 0; i < n; i++) {
char records[10000][15];
int records_size = 0;
// 读取一行考勤记录
while (scanf("%s", records[records_size++])) {
if (getchar() != ' ') break;
}
// 调用 isAward 函数判断是否能获得出勤奖
puts(isAward(records, records_size) ? "true" : "false");
}
return 0;
}
代码逻辑详解
1. 输入获取
- C++:
- 使用
cin
读取记录条数n
。 - 使用
getline
读取一行考勤记录,并按空格拆分为vector<string>
。
- 使用
- C语言:
- 使用
scanf
读取记录条数n
。 - 使用
scanf
和getchar
读取一行考勤记录,并按空格拆分为二维字符数组。
- 使用
2. isAward
函数
- 功能:判断单条考勤记录是否满足出勤奖的条件。
- 变量说明:
absent
:统计缺勤次数。present
:统计滑窗内正常上班的次数。preRecord
:记录前一次的考勤记录,用于判断是否有连续的迟到/早退。
- 遍历考勤记录:
- 滑窗逻辑:
- 滑窗长度最大为7。
- 如果当前索引
i >= 7
,则滑窗左边界右移,失去的部分是records[i - 7]
。 - 如果失去的部分是
present
,则滑窗内present
次数减1。
- 当前考勤记录处理:
absent
:- 缺勤次数加1。
- 如果缺勤次数 > 1,返回
false
。
late
或leaveearly
:- 检查前一次考勤记录是否是
late
或leaveearly
。 - 如果是,则存在连续的迟到/早退,返回
false
。
- 检查前一次考勤记录是否是
present
:- 滑窗内
present
次数加1。
- 滑窗内
- 更新前一次考勤记录:
- 将当前考勤记录赋值给
preRecord
。
- 将当前考勤记录赋值给
- 滑窗内缺勤/迟到/早退次数检查:
- 计算滑窗长度
window_len
(当前索引 + 1,最大为7)。 - 如果滑窗长度减去
present
次数 > 3,返回false
。
- 计算滑窗长度
- 滑窗逻辑:
- 返回结果:
- 如果所有条件都满足,返回
true
。
- 如果所有条件都满足,返回
3. 主函数
- 功能:
- 读取输入数据并解析。
- 调用
isAward
函数判断每条考勤记录是否能获得出勤奖。 - 输出结果。
示例运行
输入:
2
present
present absent present present leaveearly present absent
输出:
true
false
解析:
- 第一条记录:
- 只有
present
,满足所有条件,输出true
。
- 只有
- 第二条记录:
absent
出现2次,不满足条件1。- 存在
leaveearly
和absent
,但未连续,满足条件2。 - 滑动窗口检查发现某些窗口内
absent
、late
、leaveearly
的总次数 > 3,不满足条件3。 - 输出
false
。
总结
- 代码通过遍历考勤记录,结合滑动窗口和状态统计,高效判断是否满足出勤奖的条件。
- 核心逻辑集中在
isAward
函数中,通过滑窗和状态检查实现条件判断。
六、尾言
什么是华为OD?
华为OD(Outsourcing Developer,外包开发工程师)是华为针对软件开发工程师岗位的一种招聘形式,主要包括笔试、技术面试以及综合面试等环节。尤其在笔试部分,算法题的机试至关重要。
为什么刷题很重要?
-
机试是进入技术面的第一关:
华为OD机试(常被称为机考)主要考察算法和编程能力。只有通过机试,才能进入后续的技术面试环节。 -
技术面试需要手撕代码:
技术一面和二面通常会涉及现场编写代码或算法题。面试官会注重考察候选人的思路清晰度、代码规范性以及解决问题的能力。因此提前刷题、多练习是通过面试的重要保障。 -
入职后的可信考试:
入职华为后,还需要通过“可信考试”。可信考试分为三个等级:- 入门级:主要考察基础算法与编程能力。
- 工作级:更贴近实际业务需求,可能涉及复杂的算法或与工作内容相关的场景题目。
- 专业级:最高等级,考察深层次的算法以及优化能力,与薪资直接挂钩。
刷题策略与说明:
2024年8月14日之后,华为OD机试的题库转为 E卷,由往年题库(D卷、A卷、B卷、C卷)和全新题目组成。刷题时可以参考以下策略:
-
关注历年真题:
- 题库中的旧题占比较大,建议优先刷历年的A卷、B卷、C卷、D卷题目。
- 对于每道题目,建议深度理解其解题思路、代码实现,以及相关算法的适用场景。
-
适应新题目:
- E卷中包含全新题目,需要掌握全面的算法知识和一定的灵活应对能力。
- 建议关注新的刷题平台或交流群,获取最新题目的解析和动态。
-
掌握常见算法:
华为OD考试通常涉及以下算法和数据结构:- 排序算法(快速排序、归并排序等)
- 动态规划(背包问题、最长公共子序列等)
- 贪心算法
- 栈、队列、链表的操作
- 图论(最短路径、最小生成树等)
- 滑动窗口、双指针算法
-
保持编程规范:
- 注重代码的可读性和注释的清晰度。
- 熟练使用常见编程语言,如C++、Java、Python等。
如何获取资源?
-
官方参考:
- 华为招聘官网或相关的招聘平台会有一些参考信息。
- 华为OD的相关公众号可能也会发布相关的刷题资料或学习资源。
-
加入刷题社区:
- 找到可信的刷题交流群,与其他备考的小伙伴交流经验。
- 关注知名的刷题网站,如LeetCode、牛客网等,这些平台上有许多华为OD的历年真题和解析。
-
寻找系统性的教程:
- 学习一本经典的算法书籍,例如《算法导论》《剑指Offer》《编程之美》等。
- 完成系统的学习课程,例如数据结构与算法的在线课程。
积极心态与持续努力:
刷题的过程可能会比较枯燥,但它能够显著提升编程能力和算法思维。无论是为了通过华为OD的招聘考试,还是为了未来的职业发展,这些积累都会成为重要的财富。
考试注意细节
-
本地编写代码
- 在本地 IDE(如 VS Code、PyCharm 等)上编写、保存和调试代码,确保逻辑正确后再复制粘贴到考试页面。这样可以减少语法错误,提高代码准确性。
-
调整心态,保持冷静
- 遇到提示不足或实现不确定的问题时,不必慌张,可以采用更简单或更有把握的方法替代,确保思路清晰。
-
输入输出完整性
- 注意训练和考试时都需要编写完整的输入输出代码,尤其是和题目示例保持一致。完成代码后务必及时调试,确保功能符合要求。
-
快捷键使用
- 删除行可用
Ctrl+D
,复制、粘贴和撤销分别为Ctrl+C
,Ctrl+V
,Ctrl+Z
,这些可以正常使用。 - 避免使用
Ctrl+S
,以免触发浏览器的保存功能。
- 删除行可用
-
浏览器要求
- 使用最新版的 Google Chrome 浏览器完成考试,确保摄像头开启并正常工作。考试期间不要切换到其他网站,以免影响考试成绩。
-
交卷相关
- 答题前,务必仔细查看题目示例,避免遗漏要求。
- 每完成一道题后,点击【保存并调试】按钮,多次保存和调试是允许的,系统会记录得分最高的一次结果。完成所有题目后,点击【提交本题型】按钮。
- 确保在考试结束前提交试卷,避免因未保存或调试失误而丢分。
-
时间和分数安排
- 总时间:150 分钟;总分:400 分。
- 试卷结构:2 道一星难度题(每题 100 分),1 道二星难度题(200 分)。及格分为 150 分。合理分配时间,优先完成自己擅长的题目。
-
考试环境准备
- 考试前请备好草稿纸和笔。考试中尽量避免离开座位,确保监控画面正常。
- 如需上厕所,请提前规划好时间以减少中途离开监控的可能性。
-
技术问题处理
- 如果考试中遇到断电、断网、死机等技术问题,可以关闭浏览器并重新打开试卷链接继续作答。
- 出现其他问题,请第一时间联系 HR 或监考人员进行反馈。
祝你考试顺利,取得理想成绩!