华为OD机试 2024E卷题库疯狂收录中,刷题点这里
专栏导读
本专栏收录于《华为OD机试真题(Python/JS/C/C++)》。
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。
一、题目描述
在做物理实验时,为了计算物体移动的速度,通过相机和等工具周期性的采样物体移动距离。
由于工具故障,采样数据存在误差甚至丢失。
需要通过一个算法过滤掉不正确的采样值,且不同工具的故障恢复存在差异,算法的各关门限会根据工具类型做相应的调整。
请实现一个算法,计算出给定一组采样数据中正常值的最长连续周期。
判断1个周期的采样数据 S0 是否正确的规则如下(假定物体移动速度不超过10个单位前一个采样周期 S[i-1]):
S[i] <= 0,即为错误值
S[i] < S[i-1],即为错误值
S[i] - S[i-1] >= 10,即为错误值。
其他情况为正常值。
判断工具是否故障的规则如下:
在 M 个周期内,采样数据为错误值的次数为 T(次数可以不连续),则工具故障。
判断故障恢复的条件如下:
产生故障后的 P 个周期内,采样数据一直为正常值,则故障恢复。
错误采样数据的处理方式:
检测到故障后,丢弃从故障开始到故障恢复的采样数据
在检测到工具故障之前,错误的采样数据,则由最后一个正常值代替;如果前面没有正常的采样值,则丢弃此采样数据。
给定一段周期的采样 数据列表,计算正常值的最长连续周期。
二、输入描述
故障确认周期数和故障恢复数T分别为M和T,故障恢复周期数为P。
第i个周期,检测点的状态为S[i]。
输入为两行,格式如下:
M T P
s1 s2 s3 …
M, T, 和 P 的取值范围为[1, 100000]
S 取值范围为[0, 100000],从0开始编号
三、输出描述
一行,输出正常值的最长连续周期。
四、测试用例
1、输入
10 6 3
-1 1 2 3 100 10 13 9 10
2、输出
8
3、说明
S[0]=-1 为错误,且没有前一个正常值,因此被丢弃。
S[1]=1 到 S[8]=10 中,只有 S[4]=100 和 S[7]=9, S[8]=10 是错误的,但总错误次数 3 < T=6,所以没有发生工具故障。
替换错误数据后,最长连续正常周期为 8。
五、解题思路
为了计算给定一组采样数据中正常值的最长连续周期,我们需要按照题目描述的规则对数据进行过滤,并实时跟踪最长的正常周期。
具体步骤如下:
- 判断采样数据是否正确:
- 对于每个采样点 S[i],根据前一个采样点 S[i-1] 来判断其是否正确。
- 第一个采样点 S[0] 仅需满足 S[0] > 0。
- 维护一个滑动窗口:
- 使用一个固定大小为 M 的循环数组来跟踪最近 M 个周期内的错误次数。
- 当窗口中错误次数达到或超过 T 时,标记工具为故障状态。
- 处理工具故障:
- 一旦检测到工具故障,开始丢弃数据,直到连续 P 个周期的数据均为正常值,标记工具恢复正常。
- 在故障恢复期间,错误的采样数据被丢弃。
- 替换错误数据:
- 在工具未故障的情况下,如果检测到错误的采样数据且存在前一个正常值,则用前一个正常值替换错误数据。
- 如果不存在前一个正常值,则丢弃该采样数据。
- 跟踪最长连续正常周期:
- 在数据过滤的过程中,实时更新当前连续正常周期的长度,并记录最大值。
- 通过上述步骤,可以有效过滤掉错误数据,并计算出最长的连续正常周期。
六、Python算法源码
# Python 代码实现
import sys
def main():
import sys
# 读取输入的第一行,获取 M, T, P
first_line = sys.stdin.readline().strip()
if not first_line:
first_line = sys.stdin.readline().strip()
M, T, P = map(int, first_line.split())
# 读取第二行,获取所有采样数据
second_line = sys.stdin.readline().strip()
S = list(map(int, second_line.split()))
N = len(S)
# 初始化滑动窗口,用于记录最近 M 个周期内的错误次数
window = [0] * M # 滑动窗口数组,大小为 M
window_error_count = 0 # 当前滑动窗口内的错误次数
window_index = 0 # 当前滑动窗口的索引
# 初始化其他变量
last_correct = None # 存储最后一个正常的采样值
current_run = 0 # 当前连续正常周期的长度
max_run = 0 # 最大连续正常周期的长度
fault_state = False # 标记是否处于故障状态
recovery_counter = 0 # 恢复计数器,记录连续正常周期数
for i in range(N):
if not fault_state:
# 判断当前采样数据是否正确
if i == 0:
is_correct = S[i] > 0
else:
is_correct = (S[i] > 0) and (S[i] >= S[i-1]) and ((S[i] - S[i-1]) < 10)
new_error_flag = 0 if is_correct else 1 # 错误标志,0表示正确,1表示错误
# 更新滑动窗口中的错误次数
window_error_count -= window[window_index] # 减去即将被替换的旧值
window[window_index] = new_error_flag # 更新当前窗口位置的错误标志
window_error_count += new_error_flag # 增加新的错误标志
window_index = (window_index + 1) % M # 滑动窗口索引向后移动
# 检查是否触发故障
if window_error_count >= T:
fault_state = True # 进入故障状态
recovery_counter = 0 # 重置恢复计数器
current_run = 0 # 重置当前连续正常周期长度
continue # 开始丢弃数据
if is_correct:
last_correct = S[i] # 更新最后一个正常值
current_run += 1 # 当前连续正常周期长度加一
if current_run > max_run:
max_run = current_run # 更新最大连续正常周期长度
else:
if last_correct is not None:
# 用最后一个正常值替换错误数据
current_run += 1 # 替换后视为正常,当前连续正常周期长度加一
if current_run > max_run:
max_run = current_run # 更新最大连续正常周期长度
else:
# 没有正常值可替换,丢弃此数据
current_run = 0 # 当前连续正常周期长度重置
else:
# 处于故障状态,丢弃数据
# 判断当前采样数据是否正确,用于恢复
if i == 0:
is_correct = S[i] > 0
else:
is_correct = (S[i] > 0) and (S[i] >= S[i-1]) and ((S[i] - S[i-1]) < 10)
if is_correct:
recovery_counter += 1 # 连续正常周期数加一
if recovery_counter >= P:
fault_state = False # 恢复正常状态
recovery_counter = 0 # 重置恢复计数器
# 重置滑动窗口
window = [0] * M
window_error_count = 0
window_index = 0
current_run = 0 # 重置当前连续正常周期长度
last_correct = None # 重置最后一个正常值
else:
recovery_counter = 0 # 出现错误,恢复计数器重置
# 输出最长连续正常周期长度
print(max_run)
if __name__ == "__main__":
main()
七、JavaScript算法源码
// JavaScript 代码实现
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
let inputLines = [];
rl.on('line', (line) => {
inputLines.push(line.trim());
if (inputLines.length === 2) {
rl.close();
}
}).on('close', () => {
// 读取第一行,获取 M, T, P
let [M, T, P] = inputLines[0].split(' ').map(Number);
// 读取第二行,获取所有采样数据
let S = inputLines[1].split(' ').map(Number);
let N = S.length;
// 初始化滑动窗口,用于记录最近 M 个周期内的错误次数
let window = new Array(M).fill(0); // 滑动窗口数组,大小为 M
let window_error_count = 0; // 当前滑动窗口内的错误次数
let window_index = 0; // 当前滑动窗口的索引
// 初始化其他变量
let last_correct = null; // 存储最后一个正常的采样值
let current_run = 0; // 当前连续正常周期的长度
let max_run = 0; // 最大连续正常周期的长度
let fault_state = false; // 标记是否处于故障状态
let recovery_counter = 0; // 恢复计数器,记录连续正常周期数
for (let i = 0; i < N; i++) {
if (!fault_state) {
// 判断当前采样数据是否正确
let is_correct;
if (i === 0) {
is_correct = S[i] > 0;
} else {
is_correct = (S[i] > 0) && (S[i] >= S[i - 1]) && ((S[i] - S[i - 1]) < 10);
}
let new_error_flag = is_correct ? 0 : 1; // 错误标志,0表示正确,1表示错误
// 更新滑动窗口中的错误次数
window_error_count -= window[window_index]; // 减去即将被替换的旧值
window[window_index] = new_error_flag; // 更新当前窗口位置的错误标志
window_error_count += new_error_flag; // 增加新的错误标志
window_index = (window_index + 1) % M; // 滑动窗口索引向后移动
// 检查是否触发故障
if (window_error_count >= T) {
fault_state = true; // 进入故障状态
recovery_counter = 0; // 重置恢复计数器
current_run = 0; // 重置当前连续正常周期长度
continue; // 开始丢弃数据
}
if (is_correct) {
last_correct = S[i]; // 更新最后一个正常值
current_run += 1; // 当前连续正常周期长度加一
if (current_run > max_run) {
max_run = current_run; // 更新最大连续正常周期长度
}
} else {
if (last_correct !== null) {
// 用最后一个正常值替换错误数据
current_run += 1; // 替换后视为正常,当前连续正常周期长度加一
if (current_run > max_run) {
max_run = current_run; // 更新最大连续正常周期长度
}
} else {
// 没有正常值可替换,丢弃此数据
current_run = 0; // 当前连续正常周期长度重置
}
}
} else {
// 处于故障状态,丢弃数据
// 判断当前采样数据是否正确,用于恢复
let is_correct;
if (i === 0) {
is_correct = S[i] > 0;
} else {
is_correct = (S[i] > 0) && (S[i] >= S[i - 1]) && ((S[i] - S[i - 1]) < 10);
}
if (is_correct) {
recovery_counter += 1; // 连续正常周期数加一
if (recovery_counter >= P) {
fault_state = false; // 恢复正常状态
recovery_counter = 0; // 重置恢复计数器
// 重置滑动窗口
window = new Array(M).fill(0);
window_error_count = 0;
window_index = 0;
current_run = 0; // 重置当前连续正常周期长度
last_correct = null; // 重置最后一个正常值
}
} else {
recovery_counter = 0; // 出现错误,恢复计数器重置
}
}
}
// 输出最长连续正常周期长度
console.log(max_run);
});
八、C算法源码
/* C 代码实现 */
#include <stdio.h>
#include <stdlib.h>
int main(){
int M, T, P;
// 读取 M, T, P
scanf("%d %d %d", &M, &T, &P);
// 读取第二行的采样数据
// 假设最大采样数量为100000,动态分配
int *S = (int*)malloc(100000 * sizeof(int));
int N = 0;
while(scanf("%d", &S[N]) != EOF){
N++;
}
// 初始化滑动窗口
int *window = (int*)calloc(M, sizeof(int)); // 初始化为0
int window_error_count = 0;
int window_index = 0;
// 初始化其他变量
int last_correct = -1; // -1表示没有正常值
int current_run = 0;
int max_run = 0;
int fault_state = 0; // 0表示正常,1表示故障
int recovery_counter = 0;
for(int i=0; i<N; i++){
if(!fault_state){
// 判断当前采样数据是否正确
int is_correct;
if(i ==0){
is_correct = S[i] >0;
}
else{
is_correct = (S[i] >0) && (S[i] >= S[i-1]) && ((S[i] - S[i-1]) <10);
}
int new_error_flag = is_correct ? 0 :1;
// 更新滑动窗口中的错误次数
window_error_count -= window[window_index];
window[window_index] = new_error_flag;
window_error_count += new_error_flag;
window_index = (window_index +1) % M;
// 检查是否触发故障
if(window_error_count >= T){
fault_state = 1; // 进入故障状态
recovery_counter =0;
current_run =0; // 重置当前连续正常周期长度
continue; // 开始丢弃数据
}
if(is_correct){
last_correct = S[i];
current_run +=1;
if(current_run > max_run){
max_run = current_run;
}
}
else{
if(last_correct != -1){
// 用最后一个正常值替换错误数据
current_run +=1;
if(current_run > max_run){
max_run = current_run;
}
}
else{
// 没有正常值可替换,丢弃此数据
current_run =0;
}
}
}
else{
// 处于故障状态,丢弃数据
// 判断当前采样数据是否正确,用于恢复
int is_correct;
if(i ==0){
is_correct = S[i] >0;
}
else{
is_correct = (S[i] >0) && (S[i] >= S[i-1]) && ((S[i] - S[i-1]) <10);
}
if(is_correct){
recovery_counter +=1;
if(recovery_counter >= P){
fault_state =0; // 恢复正常状态
recovery_counter =0;
// 重置滑动窗口
for(int j=0; j<M; j++){
window[j] =0;
}
window_error_count =0;
window_index =0;
current_run =0; // 重置当前连续正常周期长度
last_correct = -1; // 重置最后一个正常值
}
}
else{
recovery_counter =0;
}
}
}
// 输出最长连续正常周期长度
printf("%d\n", max_run);
// 释放内存
free(S);
free(window);
return 0;
}
九、C++算法源码
// C++ 代码实现
#include <bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int M, T, P;
// 读取 M, T, P
cin >> M >> T >> P;
// 读取第二行的采样数据
vector<int> S;
int num;
while(cin >> num){
S.push_back(num);
}
int N = S.size();
// 初始化滑动窗口
vector<int> window(M, 0); // 滑动窗口数组,大小为 M
int window_error_count = 0;
int window_index = 0;
// 初始化其他变量
int last_correct = -1; // -1表示没有正常值
int current_run = 0;
int max_run = 0;
bool fault_state = false; // 标记是否处于故障状态
int recovery_counter = 0;
for(int i=0; i<N; i++){
if(!fault_state){
// 判断当前采样数据是否正确
bool is_correct;
if(i ==0){
is_correct = S[i] >0;
}
else{
is_correct = (S[i] >0) && (S[i] >= S[i-1]) && ((S[i] - S[i-1]) <10);
}
int new_error_flag = is_correct ? 0 :1;
// 更新滑动窗口中的错误次数
window_error_count -= window[window_index];
window[window_index] = new_error_flag;
window_error_count += new_error_flag;
window_index = (window_index +1) % M;
// 检查是否触发故障
if(window_error_count >= T){
fault_state = true; // 进入故障状态
recovery_counter =0;
current_run =0; // 重置当前连续正常周期长度
continue; // 开始丢弃数据
}
if(is_correct){
last_correct = S[i];
current_run +=1;
if(current_run > max_run){
max_run = current_run;
}
}
else{
if(last_correct != -1){
// 用最后一个正常值替换错误数据
current_run +=1;
if(current_run > max_run){
max_run = current_run;
}
}
else{
// 没有正常值可替换,丢弃此数据
current_run =0;
}
}
}
else{
// 处于故障状态,丢弃数据
// 判断当前采样数据是否正确,用于恢复
bool is_correct;
if(i ==0){
is_correct = S[i] >0;
}
else{
is_correct = (S[i] >0) && (S[i] >= S[i-1]) && ((S[i] - S[i-1]) <10);
}
if(is_correct){
recovery_counter +=1;
if(recovery_counter >= P){
fault_state = false; // 恢复正常状态
recovery_counter =0;
// 重置滑动窗口
fill(window.begin(), window.end(), 0);
window_error_count =0;
window_index =0;
current_run =0; // 重置当前连续正常周期长度
last_correct = -1; // 重置最后一个正常值
}
}
else{
recovery_counter =0;
}
}
}
// 输出最长连续正常周期长度
cout << max_run << "\n";
return 0;
}
🏆下一篇:华为OD机试真题 - 简易内存池(Python/JS/C/C++ 2024 E卷 200分)
🏆本文收录于,华为OD机试真题(Python/JS/C/C++)
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。