[LeetCode#204]Factorial Trailing Zeroes

Problem:

Description:

Count the number of prime numbers less than a non-negative number, n.

Analysis:

The idea to test if a number is prime.
Reference:
https://en.wikipedia.org/wiki/Prime_number

Prime number is an important category of problems. 
It is not hard, but require some skills in implementing.

A trivial idea for solving this problem is, test every number from "2" to "n-1" individually.
The imprtant part of this idea is how to test if a number is prime number.

One simple pattern is:
Checking if a num could be divided by an integer(larger than 1), if it is, it is not a prime number.
Definition: A prime number (or a prime) is a natural number greater than 1 that has no positive divisors other than 1 and itself.
A solution:
private boolean testPrime(int num) {
        if (num < 2)
            return false;
        for (int i = 2; i <= num / 2; i++) 
            if (num % i == 0)
                return false;
        }
        return true;
}

We need to stop i at num/2, since after that : num / i < 2 (a fractation (2, 1]). 

Actually, we stop i more early, since "after num / sqrt(num) <= sqrt(num)" which means we repeat the checking if we cointue checking. 
private boolean testPrime(int num) {
        if (num < 2)
            return false;
        for (int i = 2; i <= Math.sqrt(num); i++) {
            if (num % i == 0)
                return false;
        }
        return true;
}
Cases: 
num = 12.
1. use "for (int i = 2; i <= num / 2; i++)"
test: 2, 3, 4, 5, 6

2. use "for (int i = 2; i <= Math.sqrt(num); i++)""
test: 2, 3

test (num % 2) is no differnet than test (num % 6)
test (num % 3) is no different thant test (num % 4)
To many repeatives in the unimproved solution.

Exceed time solution:
public class Solution {
    public int countPrimes(int n) {
        if (n < 2)
            return 0;
        int count = 0;
        for (int i = 2; i < n; i++) {
            if (testPrime(i))
                count++;
        }
        return count;
    }
    
    private boolean testPrime(int num) {
        if (num < 2)
            return false;
        //for (int i = 2; i <= num / 2; i++) 
        for (int i = 2; i <= Math.sqrt(num); i++) {
            if (num % i == 0)
                return false;
        }
        return true;
    }
}

-------------------------------------------------------------------
The above solution is perfect in testing against a single integer, but for distinguishing a series of integers. The time cost is too high.
Thus we have to use "Sieve of Eratosthenes" method.
Reference:
https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes

Basic idea:
In the trivial solution, we repeatedly to check a integer against [2, ... celi(sqrt(i))]. All integer need to check against 2 , 3 ... again and again. Is that necessary, can we avoid it?

Yes, by using a check_board, we check "forward" rather than "backward"!
For a prime number p, we tag all its mulitple "p*2" "p*3" .... 
Thus each number actually only check against with one number. 
For the detail of the algorithm, please refer the reference link.

Skill:
1. if we tag sequentially, the left-most untagged number must be prime number. 
Since all numbers smaller than it could not be a divisor of it (otherwise, the number was tagged). Not to say the number large than it.

2. to tag non-prime number, we only need to start from "i^2" then "i^2+i" ...
The reason is simple. all (i-1) * i has already been tested. 
for (int j = i*i; j < n; j=j+i) {
    check_board[j] = false;
}

Efficient Soltuion:

public class Solution {
    public int countPrimes(int n) {
        if (n < 2)
            return 0;
        boolean[] check_board = new boolean[n+1];
        //note this pitfall!!!
        Arrays.fill(check_board, true);
        int count = 0;
        for (int i = 2; i < n; i++) {
            if (i < Math.sqrt(n)) {
                if (check_board[i] == false) {
                    continue;
                } else{
                    count++;
                    for (int j = i*i; j < n; j=j+i) {
                        check_board[j] = false;
                    }
                }
            } else {
                if (check_board[i] == true)
                    count++;
            }
        }
        return count;
    }
}

Clear Solution:

public class Solution {
    public int countPrimes(int n) {
        if (n < 2)
            return 0;
        boolean[] check_board = new boolean[n+1];
        //note this pitfall!!!
        Arrays.fill(check_board, true);
        int count = 0;
        for (int i = 2; i < n; i++) {
            if (i < Math.sqrt(n) && check_board[i] == true) {
                for (int j = i*i; j < n; j=j+i) {
                    check_board[j] = false;
                }
            } 
        }
        for (int i = 2; i < n; i++) {
            if (check_board[i] == true)
                count++;
        }
        return count;
    }
}

 

posted @ 2015-09-01 03:00  airforce  阅读(141)  评论(0)    收藏  举报