原题

寻找最佳阈值R语言 最佳阈值的确定_算法

题意

简单来说就是给m位同学分别赋2个值,安全阀值和其是否挂科(0代表挂科、1代表未挂科),要求求出m个同学中的最佳阀值,其中最佳阀值的解释是:若任意同学的原本的阀值小于该最佳阀值且该同学挂科,或任意同学的原本阀值大于或等于该最佳阀值且该同学未挂科,此时这些满足条件的同学的数量最多的阀值为最佳阀值,当有俩个或以上的阀值求的满足条件的数量相同时,取最大阀值作为最佳阀值。

思路

初做此题的同学可能想使用二重循环分别求出每个同学的阀值对应的满足条件的数量,但是却只有70的分,要想取得100分,必须优化代码使其能在规定时间内完成剩余2<=m<=10^5的测试数据。

优化方式为将m位同学的安全阀值进行递增排序,并设置一个结构体存储俩个数据:存储到第i位同学为止出现过0(挂科)的次数y1(i)和出现过1(未挂科) 的次数y2(i)。
则第i位同学的阀值对应的预测成功次数=小于该阀值且挂科的人数+大于等于该阀值且没有挂科的人数
其中小于该阀值且挂科的人数=y1(i)
而大于等于该阀值且没有挂科的人数=所有没挂科的人数 - 当前学生前所有没的挂科人数=y2(m-1)-y2(i-1)

其中需要注意在此优化算法中重复项可能会导致计算错误,因为若前一位同学的阀值跟此时遍历到的同学的阀值是相同且上一位同学挂科了,按照此算法会将上一位同学作为阀值小于自己的进行计算,所以只需要计算相同阀值中的第一个即可避免此错误,在循环中设置if语句判断当前同学的阀值是否与上面一位同学的相同,若相同则跳过该次循环。

代码

#include<iostream>
#include<algorithm>

using namespace std;

struct node//存储每位同学的信息
{
	int x1;//阀值——安全指数
	int x2;//挂科否
}c[100000];

struct node2 {//存储所有的阀值
	int y1; //到第i个数组为止0的数目 0 : 挂科了
	int y2;//到第i个数组为止1的数目 1:没挂科
}d[100000];

bool cmp (node x, node y) {//sort排序函数参数,设置sort为按照阀值递增排序
	return x.x1 < y.x1;
}

int main() {
	int m;//同学总数
	cin >> m;
	int  x=0,k;
	int s=0;
	if (c[0].x2 == 0) {
		d[0].y1 = 1;
		d[0].y2 = 0;
	}
	else {
		d[0].y1 = 0;
		d[0].y2 = 1;
	}
	
	for (int i = 0; i < m; i++)
	{
		cin >> c[i].x1>> c[i].x2;
	}
	sort(c, c + m, cmp);
	for (int i = 1; i < m; i++) {//存储所有的阀值
		if (c[i].x2 == 0) {
			d[i].y1 = d[i - 1].y1 + 1;
			d[i].y2 = d[i - 1].y2 + 0;
		}
		else {
			d[i].y1 = d[i - 1].y1 + 0;
			d[i].y2 = d[i - 1].y2 + 1;
		}
	}
	k = d[m - 1].y2;//k值为遍历到的最大成功预测数目,先设置为第一位同学对应的数目
	s = c[0].x1;//s为最终输出最佳阀值
	for (int i = 1; i < m; i++) {
		if (c[i].x1 == c[i - 1].x1) {
			continue;
		}
		x = d[i - 1].y1 +d[m-1].y2- d[i-1].y2;//x为当前同学的阀值成功预测数目
		if (x >k) {
			k = x;
			s = c[i].x1;
		}
		else  if (x == k) {
			s = c[i].x1;
		}
	}
	cout << s;

	return 0;
}