我得到一个整数N,我必须找到前面只有2,3和/或5可以除的N个元素,而不是任何其他素数。
例如:
N = 3
Results: 2,3,4
N = 5
Results: 2,3,4,5,6
错误编号= 55..55 / 5 = 11..11这是一个素数。由于55..55可以被不同于2,3和5的素数除,所以它不算数。
我想我需要一个递归函数,但我无法想象算法会是什么样子
答案 0 :(得分:2)
只能被2,3或5整除的唯一数字是权力2 i ×3 j ×5 k i , j , k = 0,1 ,....
这些数字很容易生成。
答案 1 :(得分:2)
您要搜索的数字的格式为2^n * 3^m * 5^k
,其中n,m和k为正整数,n+m+k > 0
。
我预先生成一个已排序的数组,然后打印出第一个N
。
答案 2 :(得分:2)
我们可以通过合并汉明数列的适当倍数来有效地生成序列,即经典算法。
如果n > 1
是可被p
整除的汉明号码,则n/p
也是汉明号码,如果m
是汉明号码且p
2,3或5中的一个,然后m*p
也是汉明数字。
所以我们可以将汉明数的序列描述为
H = 1 : (2*H ∪ 3*H ∪ 5*H)
其中p*H
是通过将所有汉明数乘以p
获得的排序序列,∪
表示已排序的联合(因此使用H = 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, ...
,例如2*H = 2, 4, 6, 8, 10, 12, 16, 18, 20, 24, ...
}和2*H ∪ 3*H = (2, 4, 6, 8, 10, 12, 16, ...) ∪ (3, 6, 9, 12, 15, ...) = (2, 3, 4, 6, 8, 9, 10, 12, 15, 16, ...)
)。
但该算法有两个缺点。首先,它产生必须在合并(∪
)步骤中消除的重复项。其次,要生成N
附近的汉明数字,需要知道N/5
,N/3
和N/2
附近的汉明数字,最简单的方法是保持内存中N/5
和N
之间序列的一部分,对于大型N
需要相当多的内存。
解决这两个问题的变体以5的幂序列开始,
P = 1, 5, 25, 125, 625, 3125, ...
并且在第一步中产生没有素数因子的数字,除了3或5,
T = P ∪ 3*T (= 1 : (5*P ∪ 3*T))
(除了3和5之外没有素因子的n
是5的幂(n ∈ P
),或者它可以被3整除,n/3
也没有素因子除了3和5(n ∈ 3*T
))。显然,序列P
和3*T
是不相交的,因此这里不会产生重复。
然后,最后我们通过
获得汉明数的序列H = T ∪ 2*H
同样,很明显不会产生重复项,并且要在N
附近生成汉明数字,我们需要知道T
附近的序列N
,这需要知道{{} 1}} P
附近的N
和T
附近的N/3
以及H
附近的序列N/2
。在H
和N/2
之间只保留N
的部分,在T
和N/3
之间保留N
的部分需要更少的空间而不是将H
和N/5
之间的部分保留在记忆中。
my Haskell code到C ++的粗略翻译(毫无疑问,但是我几乎没有写过C ++,我学到的C ++很古老)产生
N
这样做的工作没有太低效:
#include <iostream>
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <gmpxx.h>
class Node {
public:
Node(mpz_class n) : val(n) { next = 0; };
mpz_class val;
Node *next;
};
class ListGenerator {
public:
virtual mpz_class getNext() = 0;
virtual ~ListGenerator() {};
};
class PurePowers : public ListGenerator {
mpz_class multiplier, value;
public:
PurePowers(mpz_class p) : multiplier(p), value(p) {};
mpz_class getNext() {
mpz_class temp = value;
value *= multiplier;
return temp;
}
// default destructor is fine here
// ~PurePowers() {}
};
class Merger : public ListGenerator {
mpz_class multiplier, thunk_value, self_value;
// generator of input sequence
// to be merged with our own output
ListGenerator *thunk;
// list of our output we need to remember
// to generate the next numbers
// Invariant: list is never empty, and sorted
Node *head, *tail;
public:
Merger(mpz_class p, ListGenerator *gen) : multiplier(p) {
thunk = gen;
// first output would be 1 (skipped here, though)
head = new Node(1);
tail = head;
thunk_value = thunk->getNext();
self_value = multiplier;
}
mpz_class getNext() {
if (thunk_value < self_value) {
// next value from the input sequence is
// smaller than the next value obtained
// by multiplying our output with the multiplier
mpz_class num = thunk_value;
// get next value of input sequence
thunk_value = thunk->getNext();
// and append our next output to the bookkeeping list
tail->next = new Node(num);
tail = tail->next;
return num;
} else {
// multiplier * head->val is smaller than next input
mpz_class num = self_value;
// append our next output to the list
tail->next = new Node(num);
tail = tail->next;
// and delete old head, which is no longer needed
Node *temp = head->next;
delete head;
head = temp;
// remember next value obtained from multiplying our own output
self_value = head->val * multiplier;
return num;
}
}
~Merger() {
// delete wrapped thunk
delete thunk;
// and list of our output
while (head != tail) {
Node *temp = head->next;
delete head;
head = temp;
}
delete tail;
}
};
// wrap list generator to include 1 in the output
class Hamming : public ListGenerator {
mpz_class value;
ListGenerator *thunk;
public:
Hamming(ListGenerator *gen) : value(1) {
thunk = gen;
}
// construct a Hamming number generator from a list of primes
// If the vector is empty or contains anything but primes,
// horrible things may happen, I don't care
Hamming(std::vector<unsigned long> primes) : value(1) {
std::sort(primes.begin(), primes.end());
ListGenerator *gn = new PurePowers(primes.back());
primes.pop_back();
while(primes.size() > 0) {
gn = new Merger(primes.back(), gn);
primes.pop_back();
}
thunk = gn;
}
mpz_class getNext() {
mpz_class num = value;
value = thunk->getNext();
return num;
}
~Hamming() { delete thunk; }
};
int main(int argc, char *argv[]) {
if (argc < 3) {
std::cout << "Not enough arguments provided.\n";
std::cout << "Usage: ./hamming start_index count [Primes]" << std::endl;
return 0;
}
unsigned long start, count, n;
std::vector<unsigned long> v;
start = strtoul(argv[1],NULL,0);
count = strtoul(argv[2],NULL,0);
if (argc == 3) {
v.push_back(2);
v.push_back(3);
v.push_back(5);
} else {
for(int i = 3; i < argc; ++i) {
v.push_back(strtoul(argv[i],NULL,0));
}
}
Hamming *ham = new Hamming(v);
mpz_class h;
for(n = 0; n < start; ++n) {
h = ham->getNext();
}
for(n = 0; n < count; ++n) {
h = ham->getNext();
std::cout << h << std::endl;
}
delete ham;
return 0;
}
(Haskell版本更快,GHC可以优化惯用的Haskell,而不是优化单一的C ++)
答案 3 :(得分:0)
总是有蛮力的方式:
int[] A = int[N];
int i=0;
int j=2;
while(i<N)
{
if(j%2==0)
{
if(j/2==1 || A contains j/2)
{
A[i]=j;
i++;
}
}
else if(j%3==0)
{
if(j/3==1 || A contains j/3)
{
A[i]=j;
i++;
}
}
else if(j%5==0)
{
if(j/5==1 || A contains j/5)
{
A[i]=j;
i++;
}
}
j++;
}
对于“A contains X”部分,您可以在范围0到i-1中使用二进制搜索,因为A在那里排序。