Positive number which has no prime factor greater than k

时间:2018-02-03 08:15:59

标签: c++ algorithm c++11 c++14

I tried to create a function which takes two variables n and k.

The function returns the number of positive integers that have prime factors all less than or equal to k. The number of positive integers is limited by n which is the largest positive integer.

For example, if k = 4 and n = 10; the positive integers which have all prime factors less than or equal to 4 are 1, 2, 3, 4, 6, 8, 9, 12...(1 is always part for some reason even though its not prime) but since n is 10, 12 and higher numbers are ignored.

So the function will return 7. The code I wrote works for smaller values of n while it just keeps on running for larger values.

How can I optimize this code? Should I start from scratch and come up with a better algorithm?

int generalisedHammingNumbers(int n, int k)
{
    vector<int>store;
    vector<int>each_prime = {};

    for (int i = 1; i <= n; ++i)
    {
        for (int j = 1; j <= i; ++j)
        {
            if (i%j == 0 && is_prime(j))
            {
                each_prime.push_back(j);   //temporary vector of prime factors for each integer(i) 
            }
        }
        for (int m = 0; m<each_prime.size(); ++m)
        {
            while(each_prime[m] <= k && m<each_prime.size()-1)  //search for prime factor greater than k
            {
                ++m;
            }
            if (each_prime[m] > k);  //do nothing for prime factor greater than k
            else store.push_back(i);  //if no prime factor greater than k, i is valid, store i
        }
        each_prime = {};
    }

    return (store.size()+1);
}

bool is_prime(int x)
{
    vector<int>test;
    if (x != 1)
    {
        for (int i = 2; i < x; ++i)
        {
            if (x%i == 0)test.push_back(i);
        }
        if (test.size() == 0)return true;
        else return false;

    }
    return false;

}


int main() 
{
    long n;
    int k;
    cin >> n >> k;
    long result = generalisedHammingNumbers(n, k);
    cout << result << endl;


}

3 个答案:

答案 0 :(得分:1)

  

我应该从头开始并提出更好的算法吗?

是的......我想是的。

在我看来,这是Eratosthenes筛子的作品。

所以我建议

1)创建std::vector<bool>以通过Eratosthenes检测n

的素数

2)从您的数字池(另一个k+1

中删除从std::vector<bool>开始的素数及其倍数

3)计算池向量中的true剩余值

以下是一个完整的工作示例

#include <vector>
#include <iostream>
#include <algorithm>

std::size_t foo (std::size_t n, std::size_t k)
 {
   std::vector<bool> primes(n+1U, true);
   std::vector<bool> pool(n+1U, true);

   std::size_t const sqrtOfN = std::sqrt(n);

   // first remove the not primes from primes list (Sieve of Eratosthenes)
   for ( auto i = 2U ; i <= sqrtOfN ; ++i )
      if ( primes[i] )
         for ( auto j = i << 1 ; j <= n ; j += i )
            primes[j] = false;

   // then remove from pool primes, bigger than k, and multiples
   for ( auto i = k+1U ; i <= n ; ++i )
      if ( primes[i] )
         for ( auto j = i ; j <= n ; j += i )
            pool[j] = false;

   // last count the true value in pool (excluding the zero)
   return std::count(pool.begin()+1U, pool.end(), true);
 }

int main ()
 {
   std::cout << foo(10U, 4U) << std::endl;
 }

答案 1 :(得分:0)

Generate the primes using a sieve of Erastothenes, and then use a modified coin-change algorithm to find numbers which are products of only those primes. In fact, one can do both simultaneously like this (in Python, but is easily convertible to C++):

def limited_prime_factors(n, k):
    ps = [False] * (k+1)
    r = [True] * 2 + [False] * n
    for p in xrange(2, k+1):
        if ps[p]: continue
        for i in xrange(p, k+1, p):
            ps[i] = True
        for i in xrange(p, n+1, p):
            r[i] = r[i//p]
    return [i for i, b in enumerate(r) if b]

print limited_prime_factors(100, 3)

The output is:

[0, 1, 2, 3, 4, 6, 8, 9, 12, 16, 18, 24, 27, 32, 36, 48, 54, 64, 72, 81, 96]

Here, each time we find a prime p, we strike out all multiples of p in the ps array (as a standard Sieve of Erastothenes), and then in the r array, mark all multiples of any number that's a multiple of p whether their prime factors are all less than or equal to p.

It runs in O(n) space and O(n log log k) time, assuming n>k.

A simpler O(n log k) solution tests if all the factors of a number are less than or equal to k:

def limited_prime_factors(n, k):
    r = [True] * 2 + [False] * n
    for p in xrange(2, k+1):
        for i in xrange(p, n+1, p):
            r[i] = r[i//p]
    return [i for i, b in enumerate(r) if b]

答案 2 :(得分:0)

这是Python中的Eulerian版本(似乎比Paul Hankin快1.5倍)。我们通过将列表乘以每个素数及其幂来依次生成数字本身。

import time

start = time.time()

n = 1000000
k = 100

total = 1
a = [None for i in range(0, n+1)]
s = []
p = 1
while (p < k):
  p = p + 1

  if a[p] is None:
    #print("\n\nPrime: " + str(p))
    a[p] = True
    total = total + 1
    s.append(p)

    limit = n / p
    new_s = []

    for i in s:
      j = i
      while j <= limit:
        new_s.append(j)
        #print j*p
        a[j * p] = True
        total = total + 1
        j = j * p
    s = new_s

print("\n\nGilad's answer: " + str(total))
end = time.time()
print(end - start)

# Paul Hankin's solution
def limited_prime_factors(n, k):
    ps = [False] * (k+1)
    r = [True] * 2 + [False] * n
    for p in xrange(2, k+1):
        if ps[p]: continue
        for i in xrange(p, k+1, p):
            ps[i] = True
        for i in xrange(p, n+1, p):
            r[i] = r[i//p]
    return len([i for i, b in enumerate(r) if b]) - 1

start = time.time()
print "\nPaul's answer:" + str(limited_prime_factors(1000000, 100))
end = time.time()
print(end - start)