目录
题目链接:0智慧古树的预言 - 蓝桥云课
注:下述题目描述和示例均来自蓝桥云客
题目描述
在森林中,有一棵能够预知未来的智慧古树。树下,可可与乐乐正在通过预言进行游戏。每个预言都有一个力量值,可可和乐乐各自拥有一定数量的预言。他们轮流使用力量值最大的预言。如果可可的预言力量值严格大于乐乐的,可可就取得胜利,反之乐乐获胜。当任一方使用完所有预言时,游戏结束。
现在,你需要找出在游戏中可可和乐乐各自能赢得的回合数。
输入格式
第一行包含两个整数 N 和 M,分别表示可可和乐乐拥有的预言数量。
第二行包含 N 个整数,代表可可的预言力量值。
第三行包含 M 个整数,代表乐乐的预言力量值。
输出格式
输出一行包含两个整数 A 和 B,A 表示可可赢得的回合数,B 表示乐乐赢得的回合数。
样例输入
2 2
10 1
5 5
样例输出
1 1
评测数据规模
1≤N,M≤1000
1≤v≤1000,其中 v 是预言的力量值。
解法一:直接暴力就行毕竟测试数据量不大
-
输入读取与初始化:
- 首先,程序从标准输入读取两个整数
N
和M
,分别代表两支队伍成员的数量。 - 然后,为每支队伍分配一个数组,并从标准输入读取每个成员的分数(假设分数越高表现越好)。这里,
keke
数组用于存储第一支队伍成员的分数,lele
数组用于存储第二支队伍成员的分数。
- 首先,程序从标准输入读取两个整数
-
排序:
- 对于每个队伍,使用
Arrays.sort()
(Java中)或std::sort()
(C++中)对它们的分数数组进行升序排序。排序的目的是为了后续能够高效地比较两个队伍中最强成员的实力对比。
- 对于每个队伍,使用
-
比较过程:
- 使用两个指针
s1
和s2
,分别指向keke
和lele
数组的最后一个元素(即各自队伍中分数最高的成员),并初始化两个计数器kekeWin
和leleWin
,用于记录各自的胜利次数。 - 在循环中,不断比较两个当前最高分数的成员。如果
keke
队伍的成员分数更高,则kekeWin
计数器加一;反之,leleWin
计数器加一。每次比较后,两个指针都向前移动(即向低分数方向移动),继续比较下一对成员,直到其中一个数组的所有成员都被比较完毕。
- 使用两个指针
-
输出结果:
- 最后,将两个队伍的胜利次数输出到标准输出。
-
资源管理(仅适用于C++版本):
- 由于C++中使用了动态内存分配来创建数组,在完成所有操作后,需要手动释放这些内存以避免内存泄漏。
Java写法:
import java.util.*;
// 1:无需package
// 2: 类名必须Main, 不可修改
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
// 签到题我们主打一个速度
int N = scan.nextInt();
int M = scan.nextInt();
int[] keke = new int[N];
for(int i = 0;i < N;i++){
keke[i] = scan.nextInt();
}
Arrays.sort(keke);
int[] lele = new int[M];
for(int i = 0;i < M;i++){
lele[i] = scan.nextInt();
}
Arrays.sort(lele);
int kekeWin = 0;
int leleWin = 0;
int s1 = N - 1;
int s2 = M - 1;
while(s1 >= 0 && s2 >= 0){
if(keke[s1] > lele[s2]){
kekeWin++;
}else{
leleWin++;
}
s1--;
s2--;
}
System.out.println(kekeWin + " " + leleWin);
scan.close();
}
}
C++写法:
#include <iostream>
#include <algorithm> // for std::sort
// 无需package声明和类名限制,直接实现功能
int main() {
int N, M;
std::cin >> N >> M;
int* keke = new int[N];
for(int i = 0; i < N; ++i){
std::cin >> keke[i];
}
std::sort(keke, keke + N);
int* lele = new int[M];
for(int i = 0; i < M; ++i){
std::cin >> lele[i];
}
std::sort(lele, lele + M);
int kekeWin = 0;
int leleWin = 0;
int s1 = N - 1;
int s2 = M - 1;
while(s1 >= 0 && s2 >= 0){
if(keke[s1] > lele[s2]){
kekeWin++;
} else {
leleWin++;
}
s1--;
s2--;
}
std::cout << kekeWin << " " << leleWin << std::endl;
delete[] keke; // 释放动态分配的内存
delete[] lele; // 释放动态分配的内存
return 0;
}
AC情况
慢了
时间复杂度和空间复杂度
-
输入读取:读取输入的操作是O(N + M),其中N是keke队伍成员的数量,M是lele队伍成员的数量。这个部分的时间复杂度较低,可以认为是线性的。
-
排序操作:对两个数组进行排序,分别使用
Arrays.sort()
(Java)或std::sort()
(C++)。这两个函数在平均情况下都有O(N log N)和O(M log M)的时间复杂度。这是整个算法中最耗时的部分。 -
遍历比较:在完成排序之后,程序通过一个循环来比较两队成员的成绩。这个过程最多需要min(N, M)次比较,因此时间复杂度为O(min(N, M))。这部分的时间复杂度相较于排序步骤来说较低。
综上所述,该算法的整体时间复杂度主要由排序步骤决定,即O(N log N + M log M)。这里假设了N和M的数量级相近,如果两者相差很大,则整体复杂度取决于较大数组的排序复杂度。
空间复杂度方面,除了存储输入数据所需的O(N + M)空间外,额外的空间消耗主要用于排序操作。对于大多数实现(包括Java和C++的标准库),排序算法都是原地排序(in-place sorting),这意味着它们不需要额外的、与输入大小成比例的内存空间。然而,在某些情况下(如递归实现的快速排序),可能会占用O(log N)到O(N)的额外空间用于递归调用栈。所以空间复杂度为O(N + M)。
总结
非常简单哈,不会就不礼貌了喔~~~