一、题目解析
在这道题目中,我们面临一个看似简单但实际考察细致逻辑处理的场景。题目要求统计一个数组中的元素,满足以下两个条件的元素计入统计:
- 元素本身是素数;
- 该元素的出现次数也是素数。
举例分析
-
示例1:
[1, 2, 3, 2, 5, 7, 7, 7, 5]
- 元素2:出现两次,2是素数,出现次数2也是素数,符合条件;
- 元素3:出现一次,3是素数,但1(出现次数)不是素数,不符合条件;
- 元素5:出现两次,5是素数,2(出现次数)是素数,符合条件;
- 元素7:出现三次,7是素数,3(出现次数)是素数,符合条件。
- 最终符合条件的元素数量为3。
-
示例2:
[1, 4, 6, 8, 10, 12]
- 数组中无素数元素,直接返回0。
-
示例3:
[3, 3, 3, 5, 5, 5, 5]
- 元素3:出现三次,3是素数,3(出现次数)是素数,符合条件;
- 元素5:出现四次,5是素数,但4(出现次数)不是素数,不符合条件。
- 最终符合条件的元素数量为1。
通过这些例子,可以看出本题目考察的是对素数的判断逻辑、频率统计以及双重条件筛选的综合能力。
二、思路与方法
本题可以分为以下几个步骤:
1. 素数的判断
判断一个数是否为素数是本题的核心。素数的定义是仅能被1和自身整除的自然数,因此:
- 如果数字小于等于1,则不是素数;
- 如果数字大于1,则需要检查是否有其他因子,最优方式是遍历从
2
到sqrt(数字)
,若存在整除因子,则该数不是素数。
private static boolean isPrime(int num) {
if (num <= 1) return false;
for (int i = 2; i * i <= num; i++) {
if (num % i == 0) return false; // 存在其他因子
}
return true;
}
优化:遍历到 sqrt(n)
是必要的性能提升措施,相较于直接遍历到 n
,能够显著减少循环次数。
2. 出现次数的统计
数组中某个元素的出现次数也是判断条件之一。为了统计频率,我们可以借助 HashMap
数据结构:
- 键为数组中的元素,值为其出现次数;
- 遍历数组,每遇到一个元素,就更新其对应的频率值。
Map<Integer, Integer> countMap = new HashMap<>();
for (int num : array) {
countMap.put(num, countMap.getOrDefault(num, 0) + 1);
}
3. 双重条件筛选
通过频率统计后,我们得到每个元素和对应的出现次数。接下来,需要对每个键值对进行判断:
- 判断元素是否为素数;
- 判断该元素的频率是否为素数;
- 如果两者都满足,则计入结果。
for (Map.Entry<Integer, Integer> entry : countMap.entrySet()) {
int value = entry.getKey(); // 数字本身
int frequency = entry.getValue(); // 该数字的出现次数
if (isPrime(value) && isPrime(frequency)) {
result++;
}
}
三、完整代码实现
以下是完整的代码实现,包含逻辑模块化和必要注释:
import java.util.*;
public class Main {
// 判断一个数是否为素数
private static boolean isPrime(int num) {
if (num <= 1) return false; // 1及以下不是素数
for (int i = 2; i * i <= num; i++) {
if (num % i == 0) return false; // 存在其他因子
}
return true;
}
// 主逻辑:统计符合条件的元素数量
public static int solution(List<Integer> a) {
Map<Integer, Integer> countMap = new HashMap<>();
// 统计每个数字的出现次数
for (int num : a) {
countMap.put(num, countMap.getOrDefault(num, 0) + 1);
}
int result = 0;
// 遍历统计表,判断数字及其频率是否均为素数
for (Map.Entry<Integer, Integer> entry : countMap.entrySet()) {
int value = entry.getKey(); // 数字本身
int frequency = entry.getValue(); // 该数字的出现次数
if (isPrime(value) && isPrime(frequency)) {
result++;
}
}
return result;
}
public static void main(String[] args) {
System.out.println(solution(Arrays.asList(1, 2, 3, 2, 5, 7, 7, 7, 5)) == 3);
System.out.println(solution(Arrays.asList(1, 4, 6, 8, 10, 12)) == 0);
System.out.println(solution(Arrays.asList(3, 3, 3, 5, 5, 5, 5)) == 1);
}
}
四、代码分析与优化
- 时间复杂度
- 判断素数的时间复杂度为 O(√n);
- 遍历数组统计频率需要 O(n);
- 遍历
HashMap
判断条件需要 O(k × √m),其中k
为不同数字的种类数,m
是最大频率。
最终总时间复杂度约为 O(n + k × √m)。
- 空间复杂度
HashMap
的空间复杂度为 O(k),其中k
为数组中不同数字的种类数。
- 优化建议
对于大数据量的数组,可以预先使用埃拉托色尼筛法生成素数表,快速判断是否为素数,进一步优化素数判断的性能。
五、知识总结
通过这道题,我学习和强化了以下知识点:
- 素数的高效判断:理解并实现了通过
sqrt(n)
进行素数判定的方法,避免不必要的计算。 - 频率统计的应用:利用
HashMap
快速统计数据的频率,是处理类似问题的通用技巧。 - 逻辑模块化:将素数判断、频率统计和主逻辑分离,使代码更易读、可复用。
六、学习计划与工具运用
1. 学习计划
- 每周刷 5-10 道题目,优先练习高频基础算法题目(如数组、哈希表、排序等)。
- 对错题进行归纳整理,反复练习理解错误点。
2. 工具运用
- 豆包MarsCode AI:通过 AI 解析功能快速理解题目,学习最优解法。
- 在线题库结合 AI 辅助:比如 LeetCode 或稀土掘金,结合 AI 提供的解析和解法,可以高效弥补思路不足。