二分查找&&查找素数
素数查找 && 二分查找
今天在刷洛谷的题的时候,遇到了 这道题,作为刷题人的第一直觉肯定就是去想对应的算法(狭义的算法),但是我并没有想到什么合适的算法,看了一下旁栏的算法标签,竟然空空如也。然后我就开始了正常解题(暴力枚举 和 模拟)
判断素数(一般思路)
废话不多说,先上代码 (注:本人不是很喜欢 C/C++ 里面的 Bool 类型)
int isprime(int n) {
if (n <= 1) { //对 1 和 2 这种情况进行单独判断
return 0;
} else if (n == 2) {
return 1;
} else {
int i = 0;
for (i = 2; i < n; ++i) {
if (n % i == 0) {
break;
}
}
if (i == n ) { //若 i == n 则证明循环是正常结束的,而不是因为break跳出的
return 1;
} else {
return 0;
}
}
}
-
当然 for循环也可以这样写
for(i=2; i<sqrt(n)+1; ++i)这样优化,可以大大减少循环的次数,但是需要一定的数学知识
判断素数(埃氏筛选法)
导入
-
要得到自然数n以内的全部素数,必须把不大于 根号n 的所有素数的倍数剔除,剩下的就是素数。
-
在对普通方法的 for 循环进行优化的时候,就已经提到了 根号n ,在上面的循环中,它的作用主要是为了减少循环的次数
/*
解释一些为什么是 根号n (算是数学问题,可以不看,只记住结论)
---------------------------------------------------------------------------------------------
在这里就不去说公式的推导了(个人不喜欢推导的公式)
如果一个数可以看成两个数乘积(先不论是不是素数),那么这两个 **乘数** 肯定是一大一小
(极限情况是相等)
所以说,其中较小的一个乘数的取值范围为 (1 ~ sqrt(n))
所有我们需要排查, n 能否被其中较小的积整除 即可
---------------------------------------------------------------------------------------------
我感觉我已经用了非常通俗的语言来讲述这个问题了,希望对你能有所帮助
*/埃氏筛选法的代码实现
int prime[0X7ffffff] = {0};
//返回从 1 到 n 的所有的素数
int *isprime(int n) {
int num = 0; //用来记录素数的个数
//flag[i] 代表的含义是:i 是否是素数
int *flag = (int *)malloc((n + 1) * sizeof(int));
for (int i = 0 ; i < n; ++i) {
flag[i] = 1; //初始化所有数字为素数
}
for (int i = 2; i <= sqrt(n); ++i) {
if (flag[i] == 1) {
for (int j = i * i; j <= n; j += i) {
flag[j] = 0; //将素数的倍数全部叉掉
}
}
}
for (int i = 2; i < n; ++i) {
if (flag[i] == 1) {
prime[num] = i;
num++;
}
}
return prime;
}其实这两种解法的思想是不一样的,埃氏筛选法不存在判断,而是通过排除,而第一种则是一个数一个数去判断(无论是否优化)
二分查找解素数
话说,我是怎样想到用二分查找的呢?根据二分查找的特点
-
二分查找适合用在对增删 要求不大的 有序表 中
-
从 0 到 n 还不叫有序表吗(手动狗头)
-
第一次直接模拟的时候 TML 了,也就是说时间太长了,而二分查找的时间复杂度是 logn, 接近 n
所有就很顺其自然的想到了二分查找。
一个二分查找的模板
可能你还没有了解过 二分查找 ,所有我们先用一个经典的二分查找的模板来引入这个概念
//如果目标元素存在,则返回其的下标,如果不存在返回-1;
int search(int num[], int target) {
int left = 0;
int right = sizeof(num) / sizeof(num[0]) - 1; //left 和 rigiht 代表的是下标
while (left <= right) { //当情况允许存在时(或说合理时)
int min = left + (right - left) / 2; //防止左右边界相加会直接爆掉
if (num[mid] == target) {
return mid;
} else if (num[mid] < target) {
left = mid + 1;
} else if (num[mid] > target) {
right = mid - 1;
}
}
return -1;
}二分查找本身也并不难,我觉得通过上面这个小例子,就算是没有了解过二分查找的也应该对其有一个大概的了解了
至于,有些地方我没加注释,你却又没有看明白的,建议多看几遍:(下面的话仅代表个人的观点,不喜勿喷)
-
首先是可以锻炼你对知识的理解能力(或说你学习知识的能力)
-
其实我认为,完成一件较难的事情比完成简单的事情更有成就感;
-
再者,我如果每一行都加注释,该不明白的也不一定明白(毕竟每个人理解问题的角度不一样),还会破坏我代码整体的美观度
-
最后,我这有一个听来的道理 “ 我认为,一个真正好的老师讲课时,不应该把所有的东西都讲完,要留三分让学生自己去悟,学生学的似懂非懂就会去自己思考,然后某一天,突然恍然大悟,原来是这么回事啊!如果一个老师能带动学生的思考,那么我觉得这个老师就算是一个好老师
-
当然,我没有认为我是一个老师,但我是以 及其负责任的态度 来写这篇题解的。
二分查找找素数的思路
-
第一步,打表()
-
第二步,调用二分查找,主函数一个循环进行查找目标数是否在表内。
至于打表的代码我就不再赘述了,我其实不太喜欢打表,之所以讲这个方法,只是为了引出 二分查找
一些数学味很大的代码
辗转相除
int gcd(int a, int b) {
int t;
while (b != 0) {
t = a % b;
a = b;
b = t;
}
return a;
}证明过程太数学了,放在这篇文章里不太合适,如果你感兴趣的话,可以移步哔哩哔哩
回文数判断模板
-
你可能也想知到判断回文数的函数怎么写
int ispalindrome(int num) {
int temp=num,ans=0;
while (temp!=0) {
ans=ans*10+temp%10;
temp/=10;
}
if (ans==num)
return 1;
else
return 0;
}至此,这篇题解就算是写完了。(完结撒花)
-
因为是第一次写题解,我总共花费了 165 分钟(其实不止)
-
浅浅谈一下自己对写题解的看法吧
-
写题解是一件利人利己的好事,写题解不仅可以帮你自己深入理解掌握知识点,还可以帮助别人。感谢HAL_20大佬的带动作用
-
写一篇题解很简单,但是写一篇好的题解并不容易,我昨天晚上已经规划了这篇文章的大致内容,但是仍然用了近三个小时的时间(也可能是我菜,或者表达能力不强)
-
我认为并不是说只有难题适合写题解,只要你写的有营养就好。(不知道我写的怎么样,希望大家在下面给我评论指正一下啊,我必定虚心接受所有批评,并且逐步改正)
-
以后没有什么事情的话打算三天或者两天一篇 高质量 (高质量并不是说题解的质量,而是我投入的程度)题解
-
最后,你看我都这么努力了,你不打算点个赞吗

-
-

浙公网安备 33010602011771号