【Py/Java/C++三种语言OD2023C卷真题】20天拿下华为OD笔试之【模拟】2023C-结队编程【欧弟算法】全网注释最详细分类最全的华为OD真题题解
题目描述与示例
题目描述
某部门计划通过结队编程来进行项目开发,已知该部门有 N
名员工,每个员工有独一无二的职级,每三个员工形成一个小组进行结队编程。
结队分组规则如下:
从部门中选出序号分别为i
、j
、k
的 3
名员工,他们的职级分别为 level[i], level[j], level[k]
结队小组需满足 level[i] < level[j] < level[k]
或者 level[i] > level[j] > level[k]
,其中 0 ? i < j < k < n
请你按上述条件计算可能组合的小组数量。同一员工可以参加多个小组。
输入描述
第一行输入:员工总数 n
第二行输入:按序号依次排列的员工的职级 level
,中间用空格隔开
限制:
1 ? n ? 6000
1 ? level[i] ? 10^5
输出描述
可能组合的小组数量
示例一
输入
4
1 2 3 4
输出
4
说明
可能结队成的组合 (1,2,3)
、(1,2,4)
、(1,3,4)
、(2,3,4)
。
示例二
输入
3
5 4 7
输出
0
说明
根据结队条件,我们无法为该部门组建小组
解题思路
暴力解是很容易想到的,使用三重for
循环枚举出所有的三元组并判断和计数即可,时间复杂度为O(n^3)
,无法通过10^3
的数据量。
考虑组合数学的方法。对于某一个元素nums[j]
,如果能够统计出其左边严格小于nums[j]
的元素的数量left_smaller[j]
和其右边严格大于nums[j]的数量right_greater[j]
,那么以nums[j]
为中间第二个数,且满足nums[i] < nums[j] < nums[k]
的三元组(i, j, k)
的数量为left_smaller[j] * right_greater[j]
同理,以nums[j]
为中间第二个数,且满足nums[i] > nums[j] > nums[k]
的三元组(i, j, k)
的数量为
left_greater[j] * right_smaller[j]
因此我们可以构建四个数组,left_greater
、left_smaller
、right_greater
、right_smaller
,这四个数组的长度均为n
。第j
个位置表示,位于j
的左边严格大于、位于j
的左边严格小于、位于j
的右边严格大于、位于j
的右边严格小于nums[j]
的元素个数。构建过程如下
for j in range(1, n-1):
for i in range(j):
if nums[i] > nums[j]:
left_greater[j] += 1
elif nums[i] < nums[j]:
left_smaller[j] += 1
for k in range(j+1, n):
if nums[k] > nums[j]:
right_greater[j] += 1
elif nums[k] < nums[j]:
right_smaller[j] += 1
再使用组合数学的加法原理和乘法原理统计最终结果。
ans = 0
for j in range(1, n-1):
ans += left_greater[j] * right_smaller[j]
ans += left_smaller[j] * right_greater[j]
这样就把时间复杂度从O(n^3)
降低到了O(n^2)
代码
Python
# 题目:【模拟】2023C-结队编程
# 分值:200
# 作者:闭着眼睛学数理化
# 算法:模拟/组合数学
# 代码看不懂的地方,请直接在群上提问
n = int(input())
nums = list(map(int, input().split()))
# 构建四个辅助数组
left_greater = [0] * n
left_smaller = [0] * n
right_greater = [0] * n
right_smaller = [0] * n
# 索引0和n-1不可能作为中间元素,可以不考虑
# 遍历所有的中间索引j
for j in range(1, n-1):
# j左边的元素
for i in range(j):
# 严格大于nums[j]
if nums[i] > nums[j]:
left_greater[j] += 1
# 严格小于nums[j]
elif nums[i] < nums[j]:
left_smaller[j] += 1
# j右边的元素
for k in range(j+1, n):
# 严格大于nums[j]
if nums[k] > nums[j]:
right_greater[j] += 1
# 严格小于nums[j]
elif nums[k] < nums[j]:
right_smaller[j] += 1
ans = 0
# 再次遍历所有中间索引j
# 应用组合数学的乘法原理、加法原理
for j in range(1, n-1):
ans += left_greater[j] * right_smaller[j]
ans += left_smaller[j] * right_greater[j]
print(ans)
Java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] nums = new int[n];
for (int i = 0; i < n; i++) {
nums[i] = scanner.nextInt();
}
int[] leftGreater = new int[n];
int[] leftSmaller = new int[n];
int[] rightGreater = new int[n];
int[] rightSmaller = new int[n];
for (int j = 1; j < n - 1; j++) {
for (int i = 0; i < j; i++) {
if (nums[i] > nums[j]) {
leftGreater[j]++;
} else if (nums[i] < nums[j]) {
leftSmaller[j]++;
}
}
for (int k = j + 1; k < n; k++) {
if (nums[k] > nums[j]) {
rightGreater[j]++;
} else if (nums[k] < nums[j]) {
rightSmaller[j]++;
}
}
}
int ans = 0;
for (int j = 1; j < n - 1; j++) {
ans += leftGreater[j] * rightSmaller[j];
ans += leftSmaller[j] * rightGreater[j];
}
System.out.println(ans);
}
}
C++
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> nums(n);
for (int i = 0; i < n; i++) {
cin >> nums[i];
}
vector<int> leftGreater(n, 0);
vector<int> leftSmaller(n, 0);
vector<int> rightGreater(n, 0);
vector<int> rightSmaller(n, 0);
for (int j = 1; j < n - 1; j++) {
for (int i = 0; i < j; i++) {
if (nums[i] > nums[j]) {
leftGreater[j]++;
} else if (nums[i] < nums[j]) {
leftSmaller[j]++;
}
}
for (int k = j + 1; k < n; k++) {
if (nums[k] > nums[j]) {
rightGreater[j]++;
} else if (nums[k] < nums[j]) {
rightSmaller[j]++;
}
}
}
int ans = 0;
for (int j = 1; j < n - 1; j++) {
ans += leftGreater[j] * rightSmaller[j];
ans += leftSmaller[j] * rightGreater[j];
}
cout << ans << endl;
return 0;
}
时空复杂度
时间复杂度:O(N^2)
。双重循环所需时间复杂度。
空间复杂度:O(N)
。四个列表所占空间。
华为OD算法/大厂面试高频题算法练习冲刺训练
-
华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务100+同学成功上岸!
-
课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化
-
每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!
-
60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁
-
可上全网独家的欧弟OJ系统练习华子OD、大厂真题
-
可查看链接 大厂真题汇总 & OD真题汇总(持续更新)
-
绿色聊天软件戳
od1336
了解更多
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!