欧拉工程第41题:Pandigital prime

题目链接:https://projecteuler.net/problem=41
这个数是由1到n的数组成,并且是质数,求这样的数的最大值。

在题解论坛中看到先根据这个数是几位数,判断能不能被3整除。

1+2+3+4+5+6+7+8+9=45,1-9组成的数能被3整除
1+2+3+4+5+6+7+8=36,1-8组成的数能被3整除
1+2+3+4+5+6+7=28,1-7组成的数不能被3整除
1+2+3+4+5+6=21,1-6组成的数能被3整除
1+2+3+4+5=15,1-5组成的数能被3整除
1+2+3+4=10,1-4组成的数不能被3整除
1+2+3=6,1-3组成的数能被3整除
1+2=3,1-2组成的数能被3整除
1

根据上面结果是质数、又是1-n的数组成的,只能是1-4组成的数,或者1-7组成的数。
这样,分布在两个范围内找最大的质数就好了。

问题是如何判断这数是由1到n的数字组成的,(n最大是9,根据上面分析只能是7或4)
我用的Java中的集合相等来判断的。
具体思路:
1.这个数包含0,或者长度大于等于10,都不满足
2.将这个数中的每位数字添加到集合中
3.每添加一个元素,再第二个集合中依次添加1到n的数字
4.在添加到集合的过程如何集合的大小不等于我们添加的次数,则不满足
5.判断两个集合是否相等
6.相等则是由1到n的数组成的

为了减少不必要的运算,有1到n组成的数很少,然而质数相对多,可以先判定是1到n的数在判断 是不是质数。

还有个问题:能不能先求出这个1到n组成的数,再判断是不是质数

Java代码:

package projecteuler31to40;

import java.util.Date;
import java.util.Set;
import java.util.TreeSet;

class level41{  
    void solve(){
        long Max_Value=7654321;
        long Min_Value=1234567;
        int d=1;
        for(long i=Max_Value;i>2;i=i-2){
            if(isNDigit(i)){
                if(isPrime(i)){
                    System.out.println("OK:"+i);
                    break;
                }

            }
        }
// isPandigital(1234567,7654321);
// isPandigital(1234,4321);

    }
    void isPandigital(long min,long max){
        for(long i=max;i>=min;i=i-2){
            if(isNDigit(i)){
                if(isPrime(i)){
                    System.out.println("Pandigital:"+i);
                }

            }
        }
    }
    boolean isNDigit(long num){
        String str=String.valueOf(num);
        Set set=new TreeSet();
        Set setEqual=new TreeSet();
        if(str.indexOf("0")>-1) return false;
        if(str.length()>=10) return false;
        for(int i=0;i<str.length();i++){
            set.add(str.substring(i,i+1));
            setEqual.add(String.valueOf(i+1));
            if(set.size()< (i+1)){
                return false;
            }
        }
        return set.equals(setEqual);
    }
    boolean isPrime(long num){
        for(long i=2;i<=Math.sqrt(num);i++)
            if(num%i==0)
                return false;
        return true;
    }


}
public class Problem41 {


    public static void main(String[] args){
        Date beginTime=new Date();
        new level41().solve();
        Date endTime=new Date();
        long Time=endTime.getTime()-beginTime.getTime();
        System.out.println("Time:"+Time/1000+"s"+Time%1000+"ms");
    }

}

结果:

OK:7652413
Time:0s39ms

Python代码:

def isPrime(num):
    if num in (1,4):
        return False
    if num in (2,3):
        return True
    for i in range(2,int(num**0.5)+1):
        if num%i==0:
            return False
    return True

def getN_Set(n):
    digits=set()
    for i in range(1,n+1):
        digits.add(str(i))
    return digits

def isN_Digit(num):
    p=str(num)
    if len(p)>=10:
        return False
    if p.find('0')!=-1:
        return False
    return getN_Set(len(p))==set(p)

from time import time
t0=time()
for i in range(7654321,1234567,-2):
    if isN_Digit(i):
        if isPrime(i):
            print i
            break
t1=time()

print t1-t0

结果:

7652413
>>> t1=time()
>>> 
>>> print t1-t0
2.81699991226

Python程序,也是根据Java的程序改写的,有很多相同的地方。

在题解论坛中看到下面的Python程序:

import itertools, math

def isPrime(n):
    if n < 2:
        return False
    elif n < 4:
        return True
    elif n % 2 == 0 or n % 3 == 0:
        return False
    i=5
    for i in range(5,int(math.sqrt(n))+1,6):
        if n % i == 0 or n % (i + 2) == 0:
            return False
    return True


gen = [ int(''.join(p))  for p in itertools.permutations("7654321") ]

for i in gen:
    if isPrime(i):
        print(i)
        break

根据程序可以看出:gen保存着所有的1到7的所有组合的数。

itertools 是个Python中的迭代器模块,有时间研究下。

上面判定质数与法四很类似。

根据Python可以直接求出了1到n组合的数,用Java等能不能写出来?
题解论坛有,也就是对1-n,n个数的所有排列形式,有A(n,n)种
脑容量不够,有时间再写。

插曲:关与质数的判断方法

法一:

boolean isPrime(long num){
        for(long i=2;i<num;i++)
            if(num%i==0)
                return false;
        return true;
    }

这个时间复杂度比较大:O(N)

法二:

boolean isPrime(long num){
        for(long i=2;i<=num/2;i++)
            if(num%i==0)
                return false;
        return true;
    }

这个之前一半,时间复杂度:O(N/2)

法三:

boolean isPrime(long num){
        for(long i=2;i<=Math.sqrt(num);i++)
            if(num%i==0)
                return false;
        return true;
    }

时间复杂度:O(sqrt(N))

这个我用的比较多,比上面两个节约好多时间的。
下面介绍的方法是在题解论坛中,看到老外用到的方法。

法四:

 boolean is_prime(int x){
    if (x == 2 || x == 3 || x == 5 || x == 7 || x == 11 || x == 13)
        return true;
    if (x < 2 || x % 2 == 0)
        return false;
    for (int i = 3; i * i <= x; i++)
        if (x % i == 0)
            return false;

    return true;
}

看到好多根据这个写的判断是质数的,许多都是大同小异。
2 3 5 7 11 13,直接返回true
1 偶数,直接返回false
其他,与法三很类似,时间复杂度是:O(sqrt(N))

粗落估算平均时间复杂度:{ N/2的是1+N/2的是O(sqrt(N/2))}/N=O(sqrt(N/2))
比法三少了好多时间的。

你可能感兴趣的:(java,python,排列组合,欧拉工程,质数判断)