华为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 sysdef main():import sys# 读取输入的第一行,获取 M, T, Pfirst_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 # 滑动窗口数组,大小为 Mwindow_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] > 0else: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] > 0else: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] * Mwindow_error_count = 0window_index = 0current_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, Plet [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); // 滑动窗口数组,大小为 Mlet 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, Pscanf("%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)); // 初始化为0int 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, Pcin >> M >> T >> P;// 读取第二行的采样数据vector<int> S;int num;while(cin >> num){S.push_back(num);}int N = S.size();// 初始化滑动窗口vector<int> window(M, 0); // 滑动窗口数组,大小为 Mint 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在线答疑。