题目解析一:统计素数及其出现次数为素数的元素 | 豆包MarsCode AI刷题

20 阅读5分钟

一、题目解析

在这道题目中,我们面临一个看似简单但实际考察细致逻辑处理的场景。题目要求统计一个数组中的元素,满足以下两个条件的元素计入统计:

  1. 元素本身是素数
  2. 该元素的出现次数也是素数

举例分析

  1. 示例1: [1, 2, 3, 2, 5, 7, 7, 7, 5]

    • 元素2:出现两次,2是素数,出现次数2也是素数,符合条件;
    • 元素3:出现一次,3是素数,但1(出现次数)不是素数,不符合条件;
    • 元素5:出现两次,5是素数,2(出现次数)是素数,符合条件;
    • 元素7:出现三次,7是素数,3(出现次数)是素数,符合条件。
    • 最终符合条件的元素数量为3。
  2. 示例2: [1, 4, 6, 8, 10, 12]

    • 数组中无素数元素,直接返回0。
  3. 示例3: [3, 3, 3, 5, 5, 5, 5]

    • 元素3:出现三次,3是素数,3(出现次数)是素数,符合条件;
    • 元素5:出现四次,5是素数,但4(出现次数)不是素数,不符合条件。
    • 最终符合条件的元素数量为1。

通过这些例子,可以看出本题目考察的是对素数的判断逻辑、频率统计以及双重条件筛选的综合能力。


二、思路与方法

本题可以分为以下几个步骤:

1. 素数的判断

判断一个数是否为素数是本题的核心。素数的定义是仅能被1和自身整除的自然数,因此:

  • 如果数字小于等于1,则不是素数;
  • 如果数字大于1,则需要检查是否有其他因子,最优方式是遍历从2sqrt(数字),若存在整除因子,则该数不是素数。
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);
    }
}


四、代码分析与优化

  1. 时间复杂度
  • 判断素数的时间复杂度为 O(√n);
  • 遍历数组统计频率需要 O(n);
  • 遍历 HashMap 判断条件需要 O(k × √m),其中 k 为不同数字的种类数,m 是最大频率。

最终总时间复杂度约为 O(n + k × √m)。

  1. 空间复杂度
  • HashMap 的空间复杂度为 O(k),其中 k 为数组中不同数字的种类数。
  1. 优化建议
    对于大数据量的数组,可以预先使用埃拉托色尼筛法生成素数表,快速判断是否为素数,进一步优化素数判断的性能。

五、知识总结

通过这道题,我学习和强化了以下知识点:

  1. 素数的高效判断:理解并实现了通过 sqrt(n) 进行素数判定的方法,避免不必要的计算。
  2. 频率统计的应用:利用 HashMap 快速统计数据的频率,是处理类似问题的通用技巧。
  3. 逻辑模块化:将素数判断、频率统计和主逻辑分离,使代码更易读、可复用。

六、学习计划与工具运用

1. 学习计划

  • 每周刷 5-10 道题目,优先练习高频基础算法题目(如数组、哈希表、排序等)。
  • 对错题进行归纳整理,反复练习理解错误点。

2. 工具运用

  • 豆包MarsCode AI:通过 AI 解析功能快速理解题目,学习最优解法。
  • 在线题库结合 AI 辅助:比如 LeetCode 或稀土掘金,结合 AI 提供的解析和解法,可以高效弥补思路不足。