第六十四天 --- 力扣-多数元素+CCF认证考试模拟练习两题
题目一
解题思路
按照题目中的计算公式即可,注意如果有负数,注意把负数变成0.
代码
//202012-1 期末预测之安全指数
#include <iostream>
#include <algorithm>
using namespace std;
int ans = 0;
int n = 0;
int main()
{
cin >> n;
for (int i = 0; i < n; i++) {
int w_i = 0, score_i = 0;
scanf("%d %d", &w_i, &score_i);
ans += w_i * score_i;
}
printf("%d", max(0, ans));
return 0;
}
(所有代码均已在力扣上运行无误)
经测试,该代码运行情况是(经过多次测试所得最短时间):
时间复杂度:O(N)
空间复杂度:O(1)
题目二:
解题思路
1、重复元素不进行判断
通过观察发现,相同元素不管在哪里,判断结果一致,所以说需要元素判重,利用unordered_set,如果出现过了,就跳过判断,可以加速。
2、利用排序将判断简化
如果是乱序的,那么按照题意,前面后面的y值都可能大于当前y,都可能小于当前y,那么没有任何规律可言了,所以不行,必须对数据进行整理归纳,当选中了一个点,比它小的要找result=0,反之找result=1,明显分大小讨论,所以对数据进行排序处理,方便统计。
3、利用前缀和加速判断
先明确,result只能在0和1之间选择。一个区间的和是3,就代表着有三个1。再者,我们只需要知道选中点(包括他自己)的右面有多少个1,左面(不包括他自己)有多少个0,所以再根据result的取值,所以完全可以通过左右侧区间的区间和,来看有多少个1,进而求出判断正确点的个数,那么求区间和,用前缀和在O(1)的时间复杂度内完成。
代码
//202012-2 期末预测之最佳阈值
#include <iostream>
#include <algorithm>
#include <unordered_set>
using namespace std;
struct record {
int y;
int result;
bool operator < (const record & r ) const {//用于sort函数进行排序
return y < r.y;//表示只比较y
}
};
record rd[100002];//记录各个数据
int m = 0;//记录总数
int ans = 0;
int cnt_right = 0;//判断
int main()
{
cin >> m;
for (int i = 1; i <= m; i++) {
scanf("%d %d", &rd[i].y, &rd[i].result);
}
sort(rd + 1, rd + m + 1);//对输入进来的数据按照y排序
for (int i = 1; i <= m; i++) {
rd[i].result += rd[i - 1].result;//对于result重整,前缀和
}
unordered_set<int> uds;//用于防止判断重复元素
int tmp_right = 0;//记录某个点它预测准确的个数
for (int i = 1; i <= m; i++) {
if (uds.count(rd[i].y)) {//如果该点已经判断过了,跳过
continue;
}
else {
uds.insert(rd[i].y);//没判断过加入集合
}
tmp_right = i - 1 + rd[0].result + rd[m].result - 2 * rd[i - 1].result;//用前缀和找判断正确的个数
if (tmp_right > cnt_right) {//更新答案
ans = rd[i].y;
cnt_right = tmp_right;
}
else if (tmp_right == cnt_right) {
ans = max(ans, rd[i].y);//判断次数相等,取二者中较大者
}
}
cout << ans;
return 0;
}
(所有代码均已在力扣上运行无误)
经测试,该代码运行情况是(经过多次测试所得最短时间):
时间复杂度:O(N)
题目三
思路:
一:用unordered_map
判断到一个数字,没出现过,则加入map并且出现次数为1,出现过了,次数++,并且判断是否满足题意,动态判断,加速,但是注意,如果一直没找到答案,但是题目中说了一定有答案,那么就说明一直计算到了最后,所以答案是最后一个元素。
二:排序规整化
1、数据零散着存放,很难找到规律,所以拿到一个混乱的数据的时候,一定要先排序规整化,再找规律!!!!!!!!!!!!!!!!
2、经过规整化,数据排好序并且相同数据在一块,根据题意一定存在众数,那么就一定存在一种数,再根据他的数量,无论他在哪,在数组中间是一定能看到她的,所以得解
三:摩尔投票
假设数组中每个不同的数字就代表一个国家,而数字的个数就代表这个国家的人数,他们在一起混战,就是每两个两个同归于尽。我们就可以知道那个人数大于数组长度一半的肯定会获胜。就算退一万步来说,其他的所有人都来攻击这个人数最多的国家,他们每两个两个同归于尽,最终剩下的也是那个众数。
代码:
一
注意:在map中添加元素方法,要item.insert(pair<int,int>(nums[i], 1));
class Solution {
public:
int majorityElement(vector<int>& nums) {
int ans = 0;
int n = nums.size();
unordered_map<int, int> item;//键:nums中的元素 值:出现次数
int i = 0;
for (; i < n; i++) {
if (!item.count(nums[i])) {
item.insert(pair<int, int>(nums[i], 1));//一定注意这里给map添加元素时候的语法
}
else {
item.at(nums[i])++;//at方法和数组的[]一致
if (item.at(nums[i]) > n / 2) {
return nums[i];
}
}
}
return nums[i - 1];
}
};
时间复杂度:O(N)
空间复杂度:O(N)
二
class Solution {
public:
int majorityElement(vector<int>& nums) {
int n = nums.size();
sort(nums.begin(), nums.end());
return nums[n / 2];
}
};
时间复杂度:O(N)
空间复杂度:O(1)
三
class Solution {
public:
int majorityElement(vector<int>& nums) {
int major = nums[0];//我国士兵
int cnt = 1;//士兵数量
for (int i = 1; i < nums.size(); i++) {
if (nums[i] == major) {//同国士兵,数量++
cnt++;
}
else {
if (cnt != 0) {//碰到别国士兵,一换一
cnt--;
}
else {
cnt = 1;//我国士兵没了,就把下一个国家士兵当成我国
major = nums[i];
}
}
}
return major;
}
};
时间复杂度:O(N)
空间复杂度:O(1)
(所有代码均已在力扣上运行无误)
经测试,该代码运行情况是(经过多次测试所得最短时间):