IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 哥德巴赫猜想:任意一个偶数都等于两个质数之和,求质数对个数 -> 正文阅读

[数据结构与算法]哥德巴赫猜想:任意一个偶数都等于两个质数之和,求质数对个数

题目描述

? 有一天路飞突发奇想,他有一个猜想,任意一个大于 2 的偶数好像总能写成 2 个质数的和。路飞查了资料,发现这个猜想很早就被一个叫哥德巴赫的人提出来了,称为哥德巴赫猜想。目前还没有证明这个猜想的正确性。路飞告诉你一个整数 n ,让你用这个数去验证。

? 注意 1 不是质数。

输入
输入一个偶数 n(2≤n≤8000000)? 。

输出
输出一个整数表示有多少对 (x,y) 满足 x+y=n(x≤y) 且x,y 均为质数。

样例输入1
10
样例输出1
2
数据规模与限定
时间限制:1 s

内存限制:64 M

直观方案:

#include <stdio.h>
#include <math.h>
int is_prime(int n){
	for(int i=2,I=sqrt(n);i<=I;i++){
		if(n%i) continue;
		return 0;
	}
	return 1;
}

int main(){
	int n,count=0;
	scanf("%d",&n);

	for(int i=2;i<=n/2;i++){
		if(is_prime(i)&&is_prime(n-i)) count++;
	}
	printf("%d",count);
	return 0;
}

对每个数都需要循环判断是否为质数,效率很低,容易超时:
在这里插入图片描述

分析

给的测试数据比较大,得从其他角度思考。

方案一:

给定数组primes,每一位初始化为0代表为质数,从i=2开始,当遇到0时,将2 * 2,2 * 3,2 * 4位置标记为1,依次类推,最终得到得primes数组,质数会被标记为0,合数标记为1。比如primes[2]=0代表2为质数,primes[9]=1代表9为合数。如果primes[i]=primes[n-1]=0,代表找到一组质数对,他们的和等于n。
代码如下:

#include <stdio.h>
#include <math.h>
#define MAX 8000000
int primes[MAX]={0};
void mark_primes(int n){	
	for(int i=2;i<=sqrt(n);i++){
		if(!primes[i]){
			for(int j=i*i;j<=n;j+=i){
				primes[j]=1;
			}
		}
	}
}


int main(){
	int n,count=0;
	scanf("%d",&n);
	mark_primes(n);
	for(int i=2;i<=n/2;i++){
		if(!primes[i]&&!primes[n-i]) count++;
	}
	printf("%d",count);
	return 0;
}

结果:
在这里插入图片描述

方案二

  1. 可以先利用素数筛,找到n以内的质数,得到primes数组
  2. 再循环查找,比如输入n为100时,2为质数,那么98是否在primes中(此时可以用二分查找)。

备注: 循环查找时,并不需要遍历整个primes,因为两个数之和如果等于n,那么必有一个小于等于n/2,另一个大于等于n/2。所以可以将primes根据n/2分成较小数部分和较大数部分,循环小数组部分得到质数1,在大数部分寻找质数2(n-质数1),如果能找到质数2,则所求质数对 +1.

代码实现:

#include <stdio.h>
#define MAX 8000000
int primes[MAX]={0};
//优化的素数筛,最后得到primes,首位表示n以内的质数总个数,后面依次为对应的质数2,3,5,7……
void get_primes(int n){	
	for(int i=2;i<=n;i++){
		if(primes[i]==0) primes[++primes[0]]=i;
		for(int j=1;i*primes[j]<=n;j++){
			primes[i*primes[j]]=1;
			if(i%primes[j]==0) break;
		}
	}
}

//二分查找,用于查找质数2是否在primes的后半段中
int bin_search(int *nums,int target,int len){
	int left=0,right=len-1,mid=0;
	while(left<=right){
		mid=left+((right-left)>>1);
		if(nums[mid]==target) return mid;
		if(nums[mid]>target) right=mid-1;
		else left=mid+1;
	}
	return -1;
}

//寻找右边界,用于查找数组中小于等于n/2的索引位置
int bin_search_right(int *nums,int target,int len){
	int left=0,right=len,mid=0;
	while(left<right){
		mid=left+((right-left)>>1);
		if(nums[mid]>target) right=mid;
		else left=mid+1;
	}
	return left-1;
}
int main(){
	int n,count=0;
	scanf("%d",&n);
	get_primes(n);
	int flag=bin_search_right(&primes[1],n/2,primes[0])+1; //flag 将primes分为两部分,前部分小于等于n/2,后部分大于等于n/2(因为可以取两个相等的质数,所以左右区间都应该取n/2);计算边界时左边界从0开始,但是实际primes中的素数从1开始,所以最后使用flag时需要+1.
	for(int i=1;i<=flag;i++){
		if(~bin_search(&primes[flag],n-primes[i],primes[0]-flag+1)) count++; //在右边能找到质数2,则count++,右边部分的长度等于总长度-左边+1(加1是因为重复取了flag边界值),即“primes[0] - flag+1
	}
	printf("%d",count);
	return 0;
}

结果:
在这里插入图片描述

小结

可以看到方案2的代码量要大于方案1,切运用到了二分查找,素数筛的方法。但是内存和时间都略优于方案1.

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-04-30 08:55:25  更:2022-04-30 08:56:11 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 5:43:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码