厄拉多塞筛法 快速求质数 /回文子串

西元前250年,希腊数学家厄拉多塞(Eeatosthese)想到了一个非常美妙的质数筛法,减少了逐一检查每个数的的步骤,可以比较简单的从一大堆数字之中,筛选出质数来,这方法被称作厄拉多塞筛法(Sieve of Eeatosthese)。

具体操作:先将 2~n 的各个数放入表中,然后在2的上面画一个圆圈,然后划去2的其他倍数;第一个既未画圈又没有被划去的数是3,将它画圈,再划去3的其他倍数;现在既未画圈又没有被划去的第一个数 是5,将它画圈,并划去5的其他倍数……依次类推,一直到所有小于或等于 n 的各数都画了圈或划去为止。这时,表中画了圈的以及未划去的那些数正好就是小于 n 的素数。

 

其实,当你要画圈的素数的平方大于 n 时,那么后面没有划去的数都是素数,就不用继续判了。如下图:

厄拉多塞筛法 快速求质数 /回文子串_第1张图片

这个介绍摘自  https://blog.csdn.net/u013291076/article/details/45575967

class Solution {
public:
    int countPrimes(int n)
    {
        int count = 0;
        bool prime[n+1];
        for(int i = 0; i < n; ++i)
        prime[i] = true;

        for(int i = 2; i <= sqrt(n); ++i)   //计数过程 
        {     //外循环优化,因为判断一个数是否为质数只需要整除到sqrt(n),反推亦然
            if(prime[i])//
            {
                for(int j = i * i; j < n; j += i)  //每次增加的是i的倍数,这是需要划掉的。
//先将 2~n 的各个数放入表中,然后在2的上面画一个圆圈,然后划去2的其他倍数;第一个既未画圈又没有被划去的数是3,将它画圈,再划去3的其他倍数;现在既未画圈又没有被划去的第一个数 是5,将它画圈,并划去5的其他倍数……依次类推,一直到所有小于或等于 n 的各数都画了圈或划去为止。这时,表中画了圈的以及未划去的那些数正好就是小于 n 的素数。
                {
                   prime[j] = false;
                }
            }      
        }
        for (int i = 2; i < n; ++i)
        {
            if (prime[i]) count++;
        }
            

        return count;    
    }
};


 

如果上面的看的不明白可以使用下面的方法。

 

完全暴力求质数的算法

public int CountPrimes(int n) 
{
    int count = 0;
	bool sign = true;
    for (int i = 2; i < n; i++)
    {
        sign = true;
        for (int j = 2; j < i; j++)
        {
            if (i % j == 0)
            {
                sign = false;
                break;
            }
        }
        if (sign)
            count++; ;
    }
    return count;
}

 

优化后的暴力算法:

  • 优化1:for (int i = 3; i < n; i+=2) //除2外的质数,都是奇数,可以去掉一半
  • 优化2 :j*j <= i 也有写成j <= sqrt(i),前面的写法更好 

一个数n如果不是素数那么一定存在若干因子(不少于2个),假设最小的因子是p,
那么p*p <= n
所以p < 根号n

  • 优化3: 因为i都是奇数,奇数%偶数一定不等于0,所以只要考虑奇数就可以了。
//优化后的暴力算法
    int countPrimes(int n) 
    {
        int count = 0;
        bool sign = true;
        if(n>2) count++;   //2是质数,并且是唯一的偶数
		//优化1
        for (int i = 3; i < n; i+=2) //除2外的质数,都是奇数
        {
            sign = true;
            for (int j = 3; j*j <= i; j+=2) 
            //优化2 :j*j <= i 也有写成j <= sqrt(i),前面的更好
            // 优化3: 因为i都是奇数,奇数%偶数一定不等于0,所以只要考虑奇数就可以了。
            {
                if (i % j == 0)
                {
                    sign = false;
                    break;
                }
            }

            if (sign)
            count++; 
        }
        return count;
    }

 

 

647. 回文子串

难度中等263收藏分享切换为英文关注反馈

给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。

具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。

示例 1:

输入: "abc"
输出: 3
解释: 三个回文子串: "a", "b", "c".

示例 2:

输入: "aaa"
输出: 6
说明: 6个回文子串: "a", "a", "a", "aa", "aa", "aaa".

注意:

  1. 输入的字符串长度不会超过1000。

解题思路       动态规划法
dp[i][j]表示从i...j是否是一个回文串
dp[i][j] = 1; 如果dp[i + 1][j - 1] == 1 && s[i] == s[j]
dp[i][j] = 0; 其余情况

代码

 

char dp[1000][1000];
class Solution {
public:
    int countSubstrings(string s) {
        int n = s.length();
        if (n == 0) {
            return 0;
        }

        memset(dp, 0, sizeof(dp));

        // 边界初始化
        int i, j, off;
        for (i = 0; i < n; i++) {
            for (off = 0; off < 2 && i + off < n; off++) {
                if (s[i] == s[i + off]) {
                    dp[i][i + off] = 1;
                }
            }
        }

        // 遍历填充dp数组
        for (i = n - 1; i >= 0; i--) {
            for (j = i + 2; j < n; j++) {
                if (dp[i + 1][j - 1] == 1 && s[i] == s[j]) {
                    dp[i][j] = 1;
                }
            }
        }

        // 统计结果
        int num = 0;

    }
};

/*
dp[i][j]表示从i...j是否是一个回文串
dp[i][j] = 1; 如果dp[i + 1][j - 1] == 1 && s[i] == s[j]
dp[i][j] = 0; 其余情况
*/

动态规划法 

class Solution {
public:
    int countSubstrings(string s) {
        int N = s.size();
        if(N == 0) return 0;
        int cnt = 0;
        bool dp[N][N];
        for(int i = 0;i < N;++i)
            dp[i][i] = true;
        for(int r = 1;r < N;++r)
            for(int l = 0;l < r;++l){
                if(s[l] == s[r] && (r-l==1 || dp[l+1][r-1])){
                    dp[l][r] = true;
                    cnt++;
                }else
                dp[l][r] = false;
            }

        return cnt+N;
    }
};

中心扩撒法:

class Solution {
public:
    int countSubstrings(string s) 
    {
        if(s.empty()) return 0;
        int res = 0;
        for(int i=0;i=0 && end 

 

你可能感兴趣的:(数据结构和算法,力扣刷题记录)