农夫约翰正在试图向埃尔茜描述他最喜欢的 USACO 竞赛,但她很难理解为什么他这么喜欢它。
他说「竞赛中我最喜欢的部分是贝茜说『现在是哞哞时间』并在整个竞赛中一直哞哞叫」。
埃尔茜仍然不理解,所以农夫约翰将竞赛以文本文件形式下载,并试图解释他的意思。
竞赛被定义为一个包含 NN 个整数的数组 a1,a2,…,aNa1,a2,…,aN。
农夫约翰定义哞叫为一个包含三个整数的数组,其中第二个整数等于第三个整数,但不等于第一个整数。
一种哞叫被称为在竞赛中发生,如果可以从数组中移除整数,直到只剩下这一哞叫。
由于贝茜据称「在整个竞赛中一直哞哞叫」,请帮助埃尔茜计算竞赛中发生的不同哞叫的数量!
两种哞叫是不同的,如果它们并非由相同的整数以相同的顺序组成。
超时代码 思路为在保存数组的时候将所有出现的数字存入map中 根据数字出现的次数指定倒数第二次出现的位置 并遍历之前所有数字 找到所有出现的数字 存入set中 最后输出set的大小
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] ints = new int[n];
HashMap map = new HashMap<>();
for (int i = 0; i < n; i++) {
ints[i] = scanner.nextInt();
if(map.containsKey(ints[i])){
map.get(ints[i]).before = map.get(ints[i]).after;
map.get(ints[i]).after = i;
}
else {map.put(ints[i],new temp(i));}
}
HashSet set = new HashSet<>();
map.forEach((key,temp) -> {
if (temp.before != -1){
for (int i = 0; i < temp.before; i++) {
if (ints[i] != key){
set.add(ints[i] +" " +key);
}
}
}
});
System.out.println(set.size());
}
}
class temp {
int before = -1;
int after = -1;
public temp(int after) {
this.after = after;
}
但时间复杂度太高了 我们考虑使用另一种方法来缩短时间
保存数组过程无法简短 但遍历倒数第二次出现的数字之前的内容 会导致重复遍历了相同的数字 浪费了时间 所以我们考虑使用map来精简 保存数组时先将所有出现的数字以及出现次数存入map
再从后往前遍历 将出现的数字和次数存入mapTemp中 将map中的次数减去
这样当mapTemp中某个数字次数为2时 就可得到倒数第二次出现的位置 同时 这时候map里面只包含该位置之前存在的数字 我们只需判断map中是否存在当前位置数字 就可得到当前数字组合的所有可能性
修改后代码
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] ints = new int[n];
HashMap map = new HashMap<>();
HashMap mapTemp = new HashMap<>();
int res = 0;
for (int i = 0; i < n; i++) {
ints[i] = scanner.nextInt();
update(map,ints[i],1);
}
for (int i = n - 1; i > 0; i--) {
update(mapTemp,ints[i],1);
update(map,ints[i],-1);
if (mapTemp.get(ints[i]) == 2){
res += map.containsKey(ints[i])?map.size() - 1:map.size();
}
}
System.out.println(res);
}
public static void update(HashMap map,int a,int b){
map.put(a,map.getOrDefault(a,0) + b);
if (map.get(a) == 0){map.remove(a);}
}