zoukankan      html  css  js  c++  java
  • 算法类——数学问题汇总

    一、最大公约数和最小公倍数

    最大公约数

    正整数a与b的最大公约数是指a与b的所有公约数中最大的那个公约数。一般用gcd(a,b)来表示a和b的最大公约数。例如4和6的最大公约数是2,3和9的最大公约数是3。而求解最大公约数常用欧几里得算法(辗转相除法)。

    定理:设a、b均为正整数,则gcd(a,b)=gcd(b,a%b)。

    递归式代码:

    int gcd(int a,int b)///递归调用
    {
        if(b==0)
        {
            return a;
        }
        gcd(b,a%b);
    }

    函数调用:

    #include<algorithm>///直接使用c++的内置函数
    using namespace std;
    __gcd(int a,int b)

    最小公倍数

    最小公倍数的求解是在最大公约数的基础上进行的。一般用lcm(a,b)来表示a和b的最小公倍数。

    这里需要用到一个公式:lcm(a,b)*gcd(a,b)=a*b
    所以 lcm(a,b) = a*b/gcd(a,b)
    但在a*b计算时有可能造成溢出,因此更恰当的写法是lcm(a,b) = a/gcd(a,b)*b

    二、素数

    素数又称质数,是指除了1和本身之外,不能被其他数整除的一类数。即对给定的正整数n,如果对任意的正整数a(1<a<n),都有n%a!=0成立,那么称n是素数,否则,如果存在a(1<a<n),有n%=0成立,那么称n为合数。应特别值得注意的是,1既不是素数,也不是合数

    素数的判断

    注意到如果在2~n-1中存在n的约数,不妨设为k,即n%k==0,那么由k*(n/k)==n可知,n/k也是n的一个约数,且k与n/k中一定满足其中一个小于等于sqrt(n),另一个大于等于sqrt(n)。

    bool isPrime(int n)
    {
        if(n<=1)
        {
            return false;
        }
        int sqr = (int)sqrt( (double)m );
        for(i=2; i<=sqr; i++)
        {
            if(n%i==0)
                return false;
    
        }
        return true;
    }

    如果n没有接近int型变量的范围上界,有更简单的写法:

    bool isPrime(int n)
    {
        if(n<=1)
        {
            return false;
        }
        for(i=2; i*i<=n; i++)
        {
            if(n%i==0)
                return false;
    
        }
        return true;
    }

    筛法求素数

    逐一判断1~n范围内的素数,总的时间复杂度很高,这里引入筛法求素数。

    筛法的理论依据,任何一个数都能拆成多个素数的乘积(唯一分解定理),其思想是筛掉范围内所有的合数,而合数由素数乘积的到,素数的倍数就是合数,那么出现一个素数,我们就筛掉它的倍数。

    素数筛法代码:

    const int maxn =101;//表长
    int prime[maxn];//存放所有素数
    int pNum=0;//素数的个数
    bool p[maxn]= {0}; //如果i是素数,p[i]为false,否则,p[i]为true 初始化为0
    void Find_Prime()
    {
        for(int i=2; i<maxn; i++)
        {
            if(p[i]==false) //如果i是素数
            {
                prime[pNum++]=i;//把素数i存放到prime数组中
                for(int j=i*2; j<maxn; j+=i)
                {
                    //筛去所有i的倍数,循环条件不能写成j<=maxn
                    p[j]=true;
                }
            }
        }
    }

    求解100以内所有素数代码:

    #include<stdio.h>
    const int maxn =101;//表长
    int prime[maxn];//存放所有素数
    int pNum=0;//素数的个数
    bool p[maxn]= {0}; //如果i是素数,p[i]为false,否则,p[i]为true 初始化为0
    void Find_Prime()
    {
        for(int i=2; i<maxn; i++)
        {
            if(p[i]==false) //如果i是素数
            {
                prime[pNum++]=i;//把素数i存放到prime数组中
                for(int j=i*2; j<maxn; j+=i)
                {
                    //筛去所有i的倍数,循环条件不能写成j<=maxn
                    p[j]=true;
                }
            }
        }
    }
    int main()
    {
        Find_Prime();
        for(int i=0; i<pNum; i++)
        {
            printf("%d ",prime[i]);
        }
        return 0;
    }

    三、质因子分解

    所谓质因子分解是指将一个正整数 n 写成一个或多个质数的乘积形式,例如 24=2*2*2*3。显然,由于最后都要归结到若干不同质数的乘积,不妨先把素数表打印出来。

    由于每个质因子都可以不止出现一次,因此不妨定义结构体 factor ,用来存放质因子及其个数,如下所示:

    struct factor
    {
        int x, cnt;    // x 为质因子,cnt 为其个数
    } fac[10];

    而有一个结论:对一个正整数 n 来说,如果它存在 [2,n] 范围内的质因子,要么这些质因子全部小于等于 sqrt(n) ,要么只存在一个大于 sqrt(n) 的质因子,而其余质因子全部小于等于 sqrt(n) 。这就给进行质因子分解提供了一个很好的思路:

      1. 枚举 1~sqrt(n) 范围内的所有质因子 p,判断 p 是否是 n 的因子。如果 p 是 n 的因子,那么给 fac 数组中增加质因子 p ,并初始化其个数为 0。然后只要 p 还是 n 的因子,就让 n 不断除以 p,每次操作令 p 的个数加 1,直到 p 不再是 n 的因子为止。如果p不是质因子,就直接跳过。

    if(n % pri[i] == 0)      // prime[i] 是质因子
    {
        fac[num].x = pri[i];//记录该质因子
        fac[num].cnt = 0;
        while(n%pri[i] == 0)   // 计算该质因子的个数
        {
            fac[num].cnt++;
            n /= pri[i];
        }
        num++;    // 不同质因子个数 +1
    }

            2. 如果在上面步骤结束后 n 仍然大于 1,说明 n 有且仅有一个大于 sqrt(n) 的质因子(有可能是n本身),这时需要把这个质因子加入 fac 数组,并令其个数为 1。

    if(n != 1)   // 存在大于 sqrt(n) 的质因子
    {
        fac[num].x = n;
        fac[num++].cnt = 1;
    }

    至此,fac 数组中存放的就是质因子分解的结果,时间复杂度为O(根号n)。 

    作者:王陸

    -------------------------------------------

    个性签名:罔谈彼短,靡持己长。做一个谦逊爱学的人!

    本站使用「署名 4.0 国际」创作共享协议,转载请在文章明显位置注明作者及出处。鉴于博主处于考研复习期间,有什么问题请在评论区中提出,博主尽可能当天回复,加微信好友请注明原因

  • 相关阅读:
    WPF概述(硬件加速及分辨率无关性)
    创建自己的Code Snippet(代码模板)
    [LeetCode]46. Restore IP Addresses复原IP地址
    [LeetCode]45. Reverse Words in a String按单词翻转字符串
    [LeetCode]44. Implement strStr()实现strStr()函数
    [LeetCode]43. Integer to Roman整数转罗马数字
    [LeetCode]42. Roman to Integer罗马数字转整数
    [LeetCode]41. String to Integer(atoi)字符串转整数
    [LeetCode]40. Valid Palinadrome有效回文串
    [LeetCode]39. Longest Valid Parentheses最长有效括号对
  • 原文地址:https://www.cnblogs.com/wkfvawl/p/14543927.html
Copyright © 2011-2022 走看看