当前位置: 首页 > news >正文

LeetCode 2761 和等于目标值的质数对

找出所有和为 n 的质数对

题目描述

给定一个整数 n,找出所有满足以下条件的质数对 [x, y]:

  • 1 ≤ x ≤ y ≤ n
  • x + y = n
  • x 和 y 均为质数

返回按 x 非递减排序的二维有序列表。若不存在这样的质数对,返回空数组。

解题思路

方法选择

我们可以采用埃拉托斯特尼筛法(Sieve of Eratosthenes)来高效筛选质数,然后遍历可能的质数对进行验证。

算法步骤

  1. 质数筛选:使用筛法预处理出所有小于等于 n 的质数。
  2. 遍历验证:遍历所有可能的 x 值,检查对应的 y = n - x 是否也是质数,并且满足 x ≤ y。

代码实现

import java.util.ArrayList;
import java.util.List;

class Solution {
    public List<List<Integer>> findPrimePairs(int n) {
        boolean[] isPrime = new boolean[n + 1];
        for (int i = 2; i <= n; i++) {
            isPrime[i] = true;
        }

        // 埃拉托斯特尼筛法标记非质数
        for (int i = 2; i * i <= n; i++) {
            if (isPrime[i]) {
                for (int j = i * i; j <= n; j += i) {
                    isPrime[j] = false;
                }
            }
        }

        List<List<Integer>> result = new ArrayList<>();
        for (int x = 2; x <= n / 2; x++) { // x最大为n/2,确保x ≤ y
            int y = n - x;
            if (isPrime[x] && isPrime[y]) {
                result.add(List.of(x, y));
            }
        }
        return result;
    }
}

代码解释

  1. 初始化质数数组

    • 创建布尔数组isPrime,索引代表数值,初始时所有大于 1 的数标记为true(假设是质数)。
  2. 筛法标记非质数

    • 从 2 开始遍历,若当前数是质数,则标记其所有倍数为非质数。
    • 外层循环i从 2 到√n,内层循环j从 i² 开始,步长为 i。
  3. 遍历验证质数对

    • 遍历 x 从 2 到 n/2(确保 x ≤ y),计算对应的 y = n - x。
    • 若 x 和 y 均为质数,则将 [x, y] 加入结果列表。

复杂度分析

  • 时间复杂度:O (n log log n),主要来自筛法的时间消耗。
  • 空间复杂度:O (n),用于存储质数标记数组。

测试示例

输入:n = 10
输出:[[3, 7], [5, 5]]

解释

  • 3 + 7 = 10,且 3 和 7 均为质数。
  • 5 + 5 = 10,且 5 是质数。

优化思路

在原始解法基础上,通过以下优化提升效率:

  1. 特殊情况处理:当 n < 4 时直接返回空列表
  2. 偶数预处理:提前标记所有偶数(除 2 外)为非质数
  3. 奇偶分离:仅处理奇数以减少循环次数

优化代码

import java.util.ArrayList;
import java.util.List;

class Solution {
    public List<List<Integer>> findPrimePairs(int n) {
        // 特殊情况:n小于4时无解
        if (n < 4) return new ArrayList<>();
        
        boolean[] isPrime = new boolean[n + 1];
        isPrime[2] = true; // 2是唯一的偶质数
        
        // 预处理所有偶数(除2外)为非质数
        for (int i = 4; i <= n; i += 2) {
            isPrime[i] = false;
        }
        
        // 初始化所有奇数为质数
        for (int i = 3; i <= n; i += 2) {
            isPrime[i] = true;
        }
        
        // 埃氏筛法优化版:仅处理奇数
        for (int i = 3; i * i <= n; i += 2) {
            if (isPrime[i]) {
                // 从i²开始,步长为2i(跳过偶数)
                for (int j = i * i; j <= n; j += 2 * i) {
                    isPrime[j] = false;
                }
            }
        }
        
        // 遍历验证质数对
        List<List<Integer>> result = new ArrayList<>();
        for (int x = 2; x <= n / 2; x++) {
            int y = n - x;
            if (isPrime[x] && isPrime[y]) {
                result.add(List.of(x, y));
            }
        }
        return result;
    }
}

优化点解析

1. 特殊情况处理

if (n < 4) return new ArrayList<>();
  • 当 n=2 时,无法找到 x≤y 的质数对
  • 当 n=3 时,可能的组合是 [2,1],但 1 不是质数
  • 直接返回空列表避免后续无效计算

2. 偶数预处理

for (int i = 4; i <= n; i += 2) {
    isPrime[i] = false;
}
  • 除 2 外的所有偶数不可能是质数
  • 直接批量标记,减少后续筛法处理量

3. 奇偶分离

for (int i = 3; i <= n; i += 2) {
    isPrime[i] = true;
}
  • 仅初始化奇数为质数候选
  • 筛法循环步长设为 2,只处理奇数

4. 筛法优化

for (int j = i * i; j <= n; j += 2 * i)
  • 从 i² 开始标记非质数(i² 是第一个未被标记的倍数)
  • 步长设为 2i,跳过所有偶数倍数

复杂度对比

维度原始解法优化解法
时间复杂度O(n log log n)O(n log log n)
空间复杂度O(n)O(n)
实际效率常规实现减少约 50% 操作量

测试示例

输入:n = 10
输出:[[3, 7], [5, 5]]

执行流程

  1. 初始化 isPrime 数组,标记 2 为质数
  2. 标记 4,6,8,10 为非质数
  3. 筛法处理奇数 3,5,7,9:
    • 3 的倍数 9 被标记为非质数
    • 5 的平方 25 超过 n=10,无需处理
  4. 遍历 x=2 到 5:
    • x=2 → y=8(非质数)
    • x=3 → y=7(质数)
    • x=5 → y=5(质数)

总结

埃拉托斯特尼筛法是解决质数问题的经典算法,通过预处理质数列表可以大大提升后续查询效率。在本题中,我们利用筛法快速得到质数集合,再通过遍历验证可能的质数对,最终在 O (n) 时间内完成所有验证操作。

这种方法在处理较大 n 值时依然高效,是解决类似问题的推荐方案。

通过以下优化手段,我们在保持理论时间复杂度的同时显著提升了实际运行效率:

  1. 提前剪枝:处理小 n 值的特殊情况
  2. 奇偶分离:减少 50% 的循环次数
  3. 倍数跳跃:更高效地标记非质数
http://www.dtcms.com/a/106407.html

相关文章:

  • Anywhere文章精读
  • c# 如何利用redis存储对象,并实现快速查询
  • 实时显示符合条件的完整宋词
  • 基于 DeepSeek 与天地图搭建创新地理信息应用
  • STM32F103低功耗模式深度解析:从理论到应用实践(上) | 零基础入门STM32第九十二步
  • 使用ctags+nvim自动更新标签文件
  • 基于springboot汽车租赁系统
  • 【百日精通JAVA | SQL篇 | 第二篇】数据库操作
  • K8S集群搭建 龙蜥8.9 Dashboard部署(2025年四月最新)
  • 云计算:数字化转型的核心引擎
  • 硬件工程师零基础入门教程(三)
  • 淘天集团Java开放岗暑期实习笔试(2025年4月2日)
  • 数据结构B树的实现
  • 3D Mapping秀制作:沉浸式光影盛宴 3D mapping show
  • Linux | I.MX6ULL内核及文件系统源码结构(7)
  • Java 基础-30-单例设计模式:懒汉式与饿汉式
  • 一份关于近期推理模型研究进展的报告
  • PostgreSQL DDL 语句基本语法概览
  • 程序化广告行业(51/89):Cookie映射与移动设备ID映射解析
  • ARC缓存淘汰算法
  • 青少年编程与数学 02-015 大学数学知识点 03课题、概率论和数理统计
  • 探索Doris:日志分析的新宠,是否能取代老牌ES?
  • 使用PyInstaller打包Python项目
  • 蓝桥杯冲刺:一维前缀和
  • C语言的continue与break
  • web前端开发-JS
  • Python爬虫第3节-会话、Cookies及代理的基本原理
  • PCL RANSAC探测空间直线(指定方向)
  • Pyspark学习一:概述
  • ARM板 usb gadget hid 模拟键鼠