采样过滤_200分_A/B卷复用_逻辑分析模拟

采样过滤

题目描述:

在做物理实验时,为了计算物体移动的速率,通过相机等工具周期性的采样物体移动距离。
由于工具故障,采样数据存在误差甚至相误的情况。
需要通过一个算法过滤掉不正确的采样值,不同工具的故意模式存在差异,算法的各关门限会根据工具类型做相应的调整。
请实现一个算法,计算出给定一组采样值中正常值的最长连续周期。
  判断第1个周期的采样数据S0是否正确的规则如下(假定物体移动速率不超过10个单元前一个采样周期S[i-1]):
    S[i] <= 0,即为错误值
    S[i] < S[i-1],即为错误值
    S[i]-S[i-1] >= 10,即为错误值。其它情况为正常值
  判断工具是否故障的规则如下:
    在M个周期内,采样数据为错误值的次数为T(次数可以不连续),则工具故障。
  判断故障恢复的条件如下:
    产生故障后的P个周期内,采样数据一直为正常值,则故障恢复
  错误采样数据的处理方式:
    检测到故障后,丢弃从故障开始到故障恢复的采样数据
    在检测到工具故障之前,错误的采样数据,则由最近一个正常值代替;如果前面没有正常的采样值,则丢弃此采样数据

给定一段周期的采样数据列表S,计算正常值的最长连续周期。

输入输出描述:

输入描述:

  故障确认周期数和故障次数门限分别为M和T,故障恢复周期数为P。
  第i个周期,检测点的状态为S[i]。
  输入为两行,格式如下:
  M T P
  s1 s2 s3 …
  M、T 和 P 的取值范围为[1100000]
  s1取值范围为[0,100000],从0开始编号

输出描述:

  一行,输出正常值的最长连续周期。

示例1:

输入:
	10 6 3
	-1 1 2 3 100 10 13 9 10
输出:
	8
说明:第1、5、6这3个周期是错误值
	  没有出现连续的10次采样中,累计错误值次数 >= 3 的情况
	  所以没有出现故障,错误项可以采取恢复
	  第1个错误项的前面没有正确值,所以第1个错误值丢掉
	  第5、6这2个周期的错误值可以用第4个周期的正确值来恢复
	  故恢复后:1 2 3 3 3 13 9 10
	  答案为8

验证示例1:

输入:
	5 2 3
	-1 1 2 3 100 10 13 9 10
输出:
	0
说明:第1、5、6这3个周期是错误值
	  且在[1, 5]这5个周期中,错误项到达了2 >= t(2),故发生故障
	  在故障发生后,没有出现连续的 3 个周期都是正常值,故障一直没有被恢复,数据全部被丢掉

验证示例2:

输入:
	5 2 3
	-1 1 2 3 100 10 13 14 15
输出:
	3
说明:第1、5、6这3个周期是错误值
	  且在[1, 5]这5个周期中,错误项到达了2 >= t(2),故发生故障
	  在故障发生后,有出现连续的 3 个周期都是正常值(最后3项都是正常值),
	  连续正常值项:3 >= P,故障在第7项之后恢复,恢复前的数据丢掉后只剩下3项:13 14 15
	  剩下的3项:13 14 15,都是正常值,保留
	  答案就是3

解题思路:

本题目比较复杂,复杂的原因一是题目描述并不是特别的清晰明了,二是逻辑复杂。下图是我个人对题目的理解,很绕,具体的代码就是根据下面这个分支流程图进行编写的。另外,后面两个示例是我自己验证举的例子:
分支图形

代码:

public static void main(String[] args) {
	Scanner scanner = new Scanner(System.in);
	String[] split = scanner.nextLine().split(" ");
	// 故障确认周期数
	int m = Integer.parseInt(split[0]);
	// 故障次数门限
	int t = Integer.parseInt(split[1]);
	// 故障恢复周期数
	int p = Integer.parseInt(split[2]);
	// 检测点状态
	int[] sampleData = Arrays.stream(scanner.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
	int n = sampleData.length;

	// 1、首先,先标记采样错误数据项,1表示错误项,0表示非错误项,2表示丢弃的数据
	int[] errorData = new int[n];
	boolean hasError = false;
	for (int i = 0; i < n; i++) {
		// S[i] <= 0、 S[i] < S[i-1]、 S[i]-S[i-1] >= 10,即为错误值。其它情况为正常值
		if (sampleData[i] <= 0
				|| (i > 0 &&
				(sampleData[i] < sampleData[i - 1] || sampleData[i] - sampleData[i - 1] >= 10))) {
			errorData[i] = 1;
			hasError = true;
		} else {
			errorData[i] = 0;
		}
	}
	
	// 没有错误项
	if (!hasError) {
	    System.out.println(n);
	    return;
	}

	// 2、已经找到错误项,要处理这些错误项,则需要根据 工具是否故障、故障是否恢复 来决定是否丢弃或者进行替换
	int index = 0;
	while (index < n) {
		// ① 检测工具是否故障发生——M个周期内,累计错误次数为T
		int countError = 0;
		int j = index;
		int start = j;

		// 开始监测:找到故障发生的开始位置(M个周期内,累计错误次数为T)
		while (j < n) {
			if (errorData[j] == 1) {
				// 统计连续的 M个周期内,累计错误次数
				start = j;
				int end = start;
				while (end < n && end < j + m) {
					if (errorData[end] == 1) {
						// 错误次数增加
						countError++;
					}
					end++;
				}
				
				if (countError >= t) {
					// 发生了故障:连续的 M个周期内,累计错误次数为 T
					j = end;
					break;
				} else {// M个周期内,错误数据 < t,没有发生故障,那么处理这 M个周期内的错误数据
					// 错误数据重置为 0
					countError = 0;
					// 工具未发生故障前,错误采样数据用最近的一个正常值来替代(有正常数据),或者丢弃掉该采样错误的数据(前面无正常数据)
					if (j > 0 && t > countError && errorData[j - 1] == 0) {
						// 用最近的一个正常值来替代
						errorData[j] = 0;
						sampleData[j] = sampleData[j - 1];
					} else {
						// 丢弃掉该采样错误的数据
						errorData[j] = 2;
					}
				}
			}
			j++;
		}

		// 3、来到这里,说明发生了工具发生故障,或者已经遍历完所有数据也没发现有故障
		// 若工具发生故障,那么需要找出工具故障恢复的点:产生故障后的P个周期内,采样数据是否一直正常,是——恢复,否——还是故障
		if (countError == t) {// 发生了工具发生故障,而不是遍历结束
			// ① 工具发生故障:丢弃从 故障开始到故障恢复之间的 采样数据
			for (int i = start; i < j; i++) {
				errorData[i] = 2;
			}

			// ② 找出工具故障恢复的点
			// 故障:[start, j - 1],这 m 个区间内。从 j 开始,找到 故障恢复点
			while (j < n) {
				if (errorData[j] == 0) {
					// 从此点开始,连续的 p 个周期是否都正常
					int k = j;
					while (k < n && errorData[k] == 0) {
						k++;
					}
					// 故障恢复
					if (k - j + 1 >= p) {
						break;
					}
				}
				// 工具发生故障且还未恢复,继续丢弃从 故障开始到故障恢复之间的 采样数据
				errorData[j] = 2;
				j++;
			}
		}

		// 发生-恢复、没发生、继续,发生-没恢复不继续
		index = j;
	}

    // 答案输出:此时只剩下:2-丢弃的数据,0-正常采样数据,找出连续最长的  0 就是答案
    int res = 0;
    int sum = 0;
    for (int item : errorData) {
        if (item != 0) {
            if (sum > res) {
                res = sum;
            }
            sum = 0;
        } else {
            sum += 1;
        }
    }
    System.out.println(Math.max(res, sum));
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值