去掉最低工资和最高工资后的工资平均值
给出一个数组,数组中的值表示每个人的工资,数组里面所有数都是不一样的,每个人的工资是唯一的,去掉一个最小的数,去掉一个最大的数,求剩余所有人的平均工资
示例 1:
最小 1000,最大 4000,去掉最小和最大的,剩下 3000 和 2000 取平均,答案是 2500
数据范围大于等于 3,也就是说去掉最大数和最小数之后,至少会剩一个数
在遍历的时候求总和,同时记录最大数和最小数,算完总和后,减去一个最大数,再减去一个最小数,就是剩下所有数的和,最后再除以 n - 2 即可
只需要扫描一遍,时间复杂度是 O( n )
class Solution {
public:
double average(vector<int>& salary) {
//定义总和
double s = 0;
//定义最大数和最小数
int maxv = INT_MIN,minv =INT_MAX;
//遍历数组里面的所有数
for(auto x : salary) {
//总和加上当前这个数
s += x;
//更新最大值
maxv = max(maxv, x);
//更新最小值
minv = min(minv, x);
}
//剩下所有数的平均数
return (s - maxv - minv) / (salary.size() - 2);
}
};
n 的第 k 个因子
求: 从小到大数,n 的第 k 个约数是什么?
示例 1:
n = 12,12 的所有约数(因子)是 1,2,3,4,6,12,需要求从小到大数它的第 3 个因子,也就是 3,返回 3 即可
如果 k 大于 n 的因子个数的话,返回 - 1
数据范围:n 和 k 都是 1000,由于 n 和 k 很小,可以直接从小到大枚举,枚举到第 k 个直接输出即可,时间复杂度为 O( n )
第十二届蓝桥杯省赛第二场C++B组真题_小雪菜本菜的博客-CSDN博客
n 的所有的约数都是成对出现的,枚举的时候只需要枚举到 √ n 就可以了,时间复杂度由 O( n ) 降到 O( √ n )
暴力做法
class Solution {
public:
int kthFactor(int n, int k) {
//从小到大枚举
for(int i = 1;i <= n;i++ )
//如果当前i是n的约数 k--
if(n % i == 0 && -- k == 0)
//如果k--后k=0答案就是i
return i;
//约数个数不足k个返回-1
return -1;
}
};
如果 d 是 n 的约数,那么 n / d 也一定是 n 的约数,所有的约数一定是成对出现的,枚举的时候可以枚举较小的一半约数即可,枚举的 d 满足 d ≤ n / d,d ≤ √ n,只需要枚举到 √ n 即可
优化做法
需要注意一种特殊情况:如果 n 是完全平方数,那么满足 x^2 = n 的因子被枚举了两次,需要忽略其中的一次。
class Solution {
public:
int kthFactor(int n, int k) {
//定义答案数组
vector<int> res;
//i从 1 开始枚举
for(int i = 1;i <= n / i;i++ ) {
//如果 n % i 等于 0 说明 i 是 n 的约数
if(n % i == 0) {
//把 i 加到数组中
res.push_back(i);
//把 n / i 加到数组中
if(i != n / i) res.push_back(n / i);
}
}
//需要排序:从小到大
sort(res.begin(),res.end());
if(k > res.size()) return -1;
return res[k - 1];
}
};
删除一个元素以后全为 1 的最长子数组
给我们一个只包含 0 和 1 的数组,要从里面删掉一个数,删完之后,求最长的一段连续的 1 有多少个?
示例 1:
1 1 0 1
可以把 0 删除后,删除 0 后,就剩 3 个 1 是连续的,答案是 3
示例 2:
删除位置 4 的 0,5 个 1 就是连续的,答案是 5
先预处理 f[ i ],表示以 i 结尾的最长连续 1 的个数,正向枚举一遍,再反向枚举一遍,空间复杂度高
也可以用双指针算法
用两个指针维护一个区间,使得这个区间中最多只有一个 0,枚举的是每一个区间的右端点 i,对于每一个 i 都要找一个最靠左的 j,使得 i 和 j 之间最多只有一个 0,对于这样一个区间,每次可以把这里面的 0 删掉,以 i 结尾的区间里面最长的长度就是 i - j + 1,i 每次往后移动一步,j 一直往后移动,直到满足区间里面最多只有一个 0 为止
每次枚举一个 i 之后,都可以求出以 i 结尾的所有区间里面最长的一个满足要求的区间
在所有的 i 里面取一个 max,就是答案
两个指针只会往前走,不会回头,每个元素只会走两遍,时间复杂度为 O( n ),空间复杂度:没有开数组,O( 1 )
class Solution {
public:
int longestSubarray(vector<int>& nums) {
//定义答案
int res = 0;
//z记录0的个数 i、j都从0开始
for(int i = 0,j = 0,z = 0;i < nums.size();i++ ) {
//判断
if(nums[i] == 0) z++;
//z > 1 表示区间中多于1个0 就把j一直往右走 直到区间里面最多只有一个0为止 如果是0就减1 不是0就不减1
while(z > 1) z -= !nums[j++];
//更新答案 区间总长度i - j + 1 注意去掉1个0
res = max(res,i - j + 1 - 1);
}
return res;
}
};
并行课程 II