ProjectEuler Problem 47: Distinct primes factors

ProjectEuler Problem 47: Distinct primes factors

Apr 7, 2014
Coding
ProjectEuler

Problem 47: Distinct primes factors #

https://projecteuler.net/problem=47

The first two consecutive numbers to have two distinct prime factors are:

14 = 2 × 7
15 = 3 × 5

The first three consecutive numbers to have three distinct prime factors are:

644 = 2² × 7 × 23
645 = 3 × 5 × 43
646 = 2 × 17 × 19.

Find the first four consecutive integers to have four distinct prime factors each. What is the first of these numbers?

分析 #

找到最靠前的四个连续的整数,它们有4个不同的质因数,并且可以写成这四个质因数的乘积(质因数可以重复使用,但必须4个都用到)。

思路:从最小的满足条件的整数 n = 2 * 3 * 5 * 7 开始往上遍历,判断每个n是否满足条件,如果找到连续的四个数满足,输出答案即可。

方法1 遍历 #

开始时:使用 beginNumber 记录满足条件的4个连续数的第一个,使用 findCnt 记录当前连续满足条件数的个数 然后:从最小的满足条件的整数 n = 2 * 3 * 5 * 7 开始往上遍历。对于每个 n,做如下处理:

  • (1) 获取其所有质因数,并通过 set 进行去重。如果去重后的质因数个数不等于 4,则 n++;否则进入下一步
  • (2) 判断 n 能否写成其所有质因数的乘积(每个质因数可以重复使用),如果可以,则满足条件 findCnt++; 如果是第一个数,则记录到beginNumber,如果是第4个数,则说明找到了满足题意的答案。输出 beginNumber 即可。

重点在于 (2) 中怎么判断 n 能否写成其所有质因数的乘积(每个质因数可以重复使用)。 方法是: 使用 n 依次去整除 n 的所有质因数,如果当前质因数可以整除,则继续尝试整除它,如果当前不能整除,则继续尝试下一个质因数。使用 set 记录每次可以整除的质因数并去重。 当所有质因数都遍历完,或者 n 已经被整除到0了,则结束。 结束后,判断set中记录的质因数个数是否等于 4,等于4在满足条件,不等于则不满足条件。

C++ #

#include <iostream>
#include <set>
#include <cmath>
#include <cstdint>

bool isPrime(int64_t n)
{
    if(n <= 1 ) return false;
    if(n == 2 || n == 3) return true;
    if(n % 2 == 0) return false;

    // 关于质数分布的规律:大于等于5的质数一定和6的倍数相邻
    // 即大于等于5的质数一定是 6x-1 和 6x+1,6x+2 ~ 6x+4 一定不是质数
    // 即大于等于5的质数一定满足 n%6==1 or n%6==5
    // https://blog.csdn.net/songyunli1111/article/details/78690447
    if(n % 6 != 1 && n % 6 != 5 ) return false;

    // 从 [5, sqrt(n)] 遍历寻找是否是其因数
    for(int64_t i=5; i * i <= n; i++){
        if( n % i == 0 ) return false;
    }
    return true;
}

int main()
{

    int beginNumber = 0; // 最终的答案,即连续4个满足条件的数中的第一个
    int findCnt = 0;     // 记录当前找到几个连续的满足条件的数

    for(int n = 210; ; n++){ //  n = 210 = 2*3*5*7

        // 找到 n 的所有的质因数并去重
        std::set<int> primeFactors;
        for(int i = 2; i*i <= n; i++){
            if(  n % i == 0 ) {
                if(isPrime(i)) primeFactors.insert(i);
                if(isPrime(n/i)) primeFactors.insert(n/i); 
            }
            if(primeFactors.size() > 4) break;
        }

        // n 的质因数不等于4个,不满足
        if(primeFactors.size() != 4){
            findCnt = 0;
            continue;
        }

        // 判断 n 能否写成 4 个质因数的乘积(每个质因数可以重复使用)
        std::set<int> f;
        int cpy = n;
        for(std::set<int>::iterator it = primeFactors.begin(); it != primeFactors.end(); ){
           if(cpy % *it == 0){
               f.insert(*it);
               cpy /= *it;
               if( cpy == 0) break;
           }else{
               it++;
           }
        }

        // 不能写成4个质因数的乘积
        if(f.size() != 4){
            findCnt = 0;
            continue;
        }

        // 可以写成4个质因数的乘积,累加 findCnt,如果已找到4个,则满足条件,结束。
        findCnt ++;
        if(findCnt == 1) beginNumber = n;
        if(findCnt == 4) {
            printf("beginNumber: %d\n", beginNumber);
            return 0;
        }
    }

    return 0;
}

Golang #

package main

import "fmt"

func isPrime(n int) bool {
	if n <= 1 {
		return false
	}

	if n == 2 || n == 3 {
		return true
	}

	if n%2 == 0 {
		return false
	}

	if n%6 != 1 && n%6 != 5 {
		return false
	}

	for i := 5; i*i <= n; i++ {
		if n%i == 0 {
			return false
		}
	}

	return true
}

func main() {
	beginNumber := 0 // 最终的答案,即连续4个满足条件的数中的第一个
	findCnt := 0     // 记录当前找到几个连续的满足条件的数

	for n := 210; ; n++ { // n = 210 = 2*3*5*7
		// 找到 n 的所有质因数并去重
		primeFactors := make(map[int]struct{}, 0) // 使用map去重
		for i := 1; i*i <= n; i++ {
			if n%i == 0 {
				if isPrime(i) {
					primeFactors[i] = struct{}{}
				}
				if isPrime(n / i) {
					primeFactors[n/i] = struct{}{}
				}

				if len(primeFactors) > 4 {
					break
				}
			}
		}

		// n 的质因数不等于4个,不满足
		if len(primeFactors) != 4 {
			findCnt = 0
			continue
		}

		// 判断 n 能否写成 4 个质因数的乘积(每个质因数可以重复使用)
		f := make(map[int]struct{}, 0)
		cpy := n
		for k := range primeFactors {

			for cpy % k == 0 {
				f[k] = struct{}{}
				cpy /= k
				if cpy == 0 {
					break
				}
			}

			if cpy == 0 {
				break
			}
		}

		// 不能写成4个质因数的乘积
		if len(f) != 4 {
			findCnt = 0
			continue
		}

		// 可以写成4个质因数的乘积,累加 findCnt,如果已找到4个,则满足条件,结束。
		findCnt++
		if findCnt == 1 {
			beginNumber = n
		}
		if findCnt == 4 {
			fmt.Printf("beginNumber: %d\n", beginNumber)
			return
		}
	}
}

Python #

import math

def isPrime(n): 
    if n <= 1 : return False
    if n == 2 or n == 3 : return True
    if n % 2 == 0 : return False

    # 关于质数分布的规律:大于等于5的质数一定和6的倍数相邻
    # 即大于等于5的质数一定是 6x-1 和 6x+1,6x+2 ~ 6x+4 一定不是质数
    # 即大于等于5的质数一定满足 n%6==1 or n%6==5
    # https://blog.csdn.net/songyunli1111/article/details/78690447
    if n % 6 != 1 and n % 6 != 5 : return False

    # 从 [5, sqrt(n)] 遍历寻找是否是其因数
    for i in range(5, int(math.sqrt(n)) + 1):
        if n % i == 0 : return False

    return True

beginNumber = 0 # 最终的答案,即连续4个满足条件的数中的第一个
findCnt = 0     # 记录当前找到几个连续的满足条件的数

n = 210 # 210 = 2*3*5*7
while True:
    # 找到 n 的所有质因数并去重
    primeFactors = set()
    for i in range(1, int(math.sqrt(n))+1):
        if n % i == 0 :
            if isPrime(i) :
                primeFactors.add(i)
            if isPrime(n / i):
                primeFactors.add(n / i)
            if len(primeFactors) > 4:
                break

    # n 的质因数不等于4个,不满足
    if len(primeFactors) != 4 :
        findCnt = 0
        n = n + 1
        continue
    
    #print(n, primeFactors)
    # 判断 n 能否写成 4 个质因数的乘积(每个质因数可以重复使用)
    f = set()
    cpy = n
    for k in primeFactors :
        while cpy % k == 0 :
            f.add(k)
            cpy = int(cpy/k)
            if cpy == 0 :
                break

        if cpy == 0 :
            break

    # 不能写成4个质因数的乘积
    if len(f) != 4 :
        findCnt = 0
        n = n + 1
        continue

    # 可以写成4个质因数的乘积,累加 findCnt,如果已找到4个,则满足条件,结束。
    findCnt = findCnt + 1
    if findCnt == 1 :
        beginNumber = n
    if findCnt == 4 :
        print("beginNumber: ", beginNumber)
        exit(0)
    n = n + 1

答案 #

134043

具体的质因数如下

134043 set([3, 491, 13, 7])
134044 set([47, 2, 31, 23])
134045 set([17, 83, 19, 5])
134046 set([11, 2, 3, 677])