华为OD机试 - 采样过滤(Python/JS/C/C++ 2024 E卷 100分)

在这里插入图片描述

华为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。

五、解题思路

为了计算给定一组采样数据中正常值的最长连续周期,我们需要按照题目描述的规则对数据进行过滤,并实时跟踪最长的正常周期。

具体步骤如下:

  1. 判断采样数据是否正确:
    • 对于每个采样点 S[i],根据前一个采样点 S[i-1] 来判断其是否正确。
    • 第一个采样点 S[0] 仅需满足 S[0] > 0。
  2. 维护一个滑动窗口:
    • 使用一个固定大小为 M 的循环数组来跟踪最近 M 个周期内的错误次数。
    • 当窗口中错误次数达到或超过 T 时,标记工具为故障状态。
  3. 处理工具故障:
    • 一旦检测到工具故障,开始丢弃数据,直到连续 P 个周期的数据均为正常值,标记工具恢复正常。
    • 在故障恢复期间,错误的采样数据被丢弃。
  4. 替换错误数据:
    • 在工具未故障的情况下,如果检测到错误的采样数据且存在前一个正常值,则用前一个正常值替换错误数据。
    • 如果不存在前一个正常值,则丢弃该采样数据。
  5. 跟踪最长连续正常周期:
    • 在数据过滤的过程中,实时更新当前连续正常周期的长度,并记录最大值。
    • 通过上述步骤,可以有效过滤掉错误数据,并计算出最长的连续正常周期。

六、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在线答疑。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哪 吒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值