二分查找&&查找素数

 

1|0素数查找 && 二分查找

1|1背景

今天在刷洛谷的题的时候,遇到了 质数口袋 这道题,作为刷题人的第一直觉肯定就是去想对应的算法(狭义的算法),但是我并没有想到什么合适的算法,看了一下旁栏的算法标签,竟然空空如也。然后我就开始了正常解题(暴力枚举模拟

1|2判断素数(一般思路)

废话不多说,先上代码 (注:本人不是很喜欢 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)

    这样优化,可以大大减少循环的次数,但是需要一定的数学知识

1|3判断素数(埃氏筛选法)

1|0导入

  • 要得到自然数n以内的全部素数,必须把不大于 根号n 的所有素数的倍数剔除,剩下的就是素数。

  • 在对普通方法的 for 循环进行优化的时候,就已经提到了 根号n ,在上面的循环中,它的作用主要是为了减少循环的次数

    /*
    解释一些为什么是 根号n (算是数学问题,可以不看,只记住结论)
    ---------------------------------------------------------------------------------------------
    在这里就不去说公式的推导了(个人不喜欢推导的公式)
    如果一个数可以看成两个数乘积(先不论是不是素数),那么这两个 **乘数** 肯定是一大一小
    (极限情况是相等)
    所以说,其中较小的一个乘数的取值范围为 (1 ~ sqrt(n))
    所有我们需要排查, n 能否被其中较小的积整除 即可
    ---------------------------------------------------------------------------------------------
    我感觉我已经用了非常通俗的语言来讲述这个问题了,希望对你能有所帮助
    */

    1|0埃氏筛选法的代码实现

    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;
    }

    1|0其实这两种解法的思想是不一样的,埃氏筛选法不存在判断,而是通过排除,而第一种则是一个数一个数去判断(无论是否优化)

    1|4二分查找解素数

    话说,我是怎样想到用二分查找的呢?根据二分查找的特点

    • 二分查找适合用在对增删 要求不大的 有序表

    • 从 0 到 n 还不叫有序表吗(手动狗头)

    • 第一次直接模拟的时候 TML 了,也就是说时间太长了,而二分查找的时间复杂度是 logn, 接近 n

    所有就很顺其自然的想到了二分查找。

    1|0一个二分查找的模板

    可能你还没有了解过 二分查找 ,所有我们先用一个经典的二分查找的模板来引入这个概念

    //如果目标元素存在,则返回其的下标,如果不存在返回-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;
    }

    二分查找本身也并不难,我觉得通过上面这个小例子,就算是没有了解过二分查找的也应该对其有一个大概的了解了

    至于,有些地方我没加注释,你却又没有看明白的,建议多看几遍:(下面的话仅代表个人的观点,不喜勿喷)

    • 首先是可以锻炼你对知识的理解能力(或说你学习知识的能力)

    • 其实我认为,完成一件较难的事情比完成简单的事情更有成就感;

    • 再者,我如果每一行都加注释,该不明白的也不一定明白(毕竟每个人理解问题的角度不一样),还会破坏我代码整体的美观度

    • 最后,我这有一个听来的道理 “ 我认为,一个真正好的老师讲课时,不应该把所有的东西都讲完,要留三分让学生自己去悟,学生学的似懂非懂就会去自己思考,然后某一天,突然恍然大悟,原来是这么回事啊!如果一个老师能带动学生的思考,那么我觉得这个老师就算是一个好老师

    • 当然,我没有认为我是一个老师,但我是以 及其负责任的态度 来写这篇题解的。

    1|0二分查找找素数的思路

    • 第一步,打表()

    • 第二步,调用二分查找,主函数一个循环进行查找目标数是否在表内。

    1|0至于打表的代码我就不再赘述了,我其实不太喜欢打表,之所以讲这个方法,只是为了引出 二分查找


    1|5一些数学味很大的代码

    1|0辗转相除

    int gcd(int a, int b) {
    int t;
    while (b != 0) {
    t = a % b;
    a = b;
    b = t;
    }
    return a;
    }

    证明过程太数学了,放在这篇文章里不太合适,如果你感兴趣的话,可以移步哔哩哔哩辗转相除的数学解释

     

    1|0回文数判断模板

    • 你可能也想知到判断回文数的函数怎么写

    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;
    }

    1|6至此,这篇题解就算是写完了。(完结撒花)

    • 因为是第一次写题解,我总共花费了 165 分钟(其实不止)

    • 浅浅谈一下自己对写题解的看法吧

      • 写题解是一件利人利己的好事,写题解不仅可以帮你自己深入理解掌握知识点,还可以帮助别人。感谢HAL_20大佬的带动作用

      • 写一篇题解很简单,但是写一篇好的题解并不容易,我昨天晚上已经规划了这篇文章的大致内容,但是仍然用了近三个小时的时间(也可能是我菜,或者表达能力不强)

      • 我认为并不是说只有难题适合写题解,只要你写的有营养就好。(不知道我写的怎么样,希望大家在下面给我评论指正一下啊,我必定虚心接受所有批评,并且逐步改正)

      • 以后没有什么事情的话打算三天或者两天一篇 高质量 (高质量并不是说题解的质量,而是我投入的程度)题解

    1|7最后,你看我都这么努力了,你不打算点个赞吗

     

  •  


__EOF__

本文作者userName
本文链接https://www.cnblogs.com/codezzzsleep/articles/15957950.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   codezzzsleep  阅读(113)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示