有效地找到一个级数中的第n个数,其中这些数只能被2,3和5整除

Efficiently find the nth number in a series where the numbers are only divisible by 2,3 and 5

本文关键字:整除 一个 有效地 个数      更新时间:2024-09-23

我想在一系列只能被2、3和5整除而不能被任何其他素数整除的数字中找到第n个数字。

这是我找到第1500个数字的最简单的解决方案。这大约需要16秒才能执行。我想知道是否有一种方法可以让它更快,比如使用多线程。

#include <iostream>
using namespace std;
int main()
{
int temp, seriesCounter = 1, currentNumber = 2;
while (seriesCounter < 1500)
{
temp = currentNumber;
//Remove all multiple of 2
while (temp % 2 == 0)
{
temp /= 2;
}
//Remove all multiple of 3
while (temp % 3 == 0)
{
temp /= 3;
}
//Remove all multiple of 5
while (temp % 5 == 0)
{
temp /= 5;
}
// If only 1 remains, the number is valid, else not.
if (temp == 1)
{
seriesCounter++;
}
currentNumber++;
}
cout << "The 1500th number in the series is : " << --currentNumber << endl << endl;
return 1;
}

这里有一个非常简单的方法。它在不到一秒钟的时间里找到了第1500个元素(我没想更精确地测量(。

#include <set>
#include <iostream>
int main() {
int n = 1500;
std::set<long long> s;
s.insert(2);
s.insert(3);
s.insert(5);
long long num = 0;
while (n--) {
num = *s.begin();
s.erase(s.begin());
s.insert(num*2);
s.insert(num*3);
s.insert(num*5);
}
std::cout << num;
}

在i7笔记本电脑上用0.000031秒完成的快速解决方案(结果:num[149]=860934420(:

时间复杂度为O(n((在您的情况下,n=1500(。假设当前序列为num[]。我们想把它增加到1500个元素。主要思想是记录序列num[]中的三个位置,我们称它们为idx[0]、idx[1]和idx[3]。使得2num[idx[0]、3num[idx[1]和5*num[idx[2]变得刚好>=序列中的最后一个数字(num.back(((。然后将三个数字中最小的一个加到序列的末尾(这将成为新的num.back(。

#include <iostream>
#include <vector>
#include <algorithm>
#include <chrono>
using std::vector;
using namespace std::chrono;
int main()
{
auto start = high_resolution_clock::now();
const vector<int> p{ 2,3,5 };
vector<int> idx{ 0,0,0 };
vector<int> num = { 2,3,4,5 }; num.reserve(1500);
vector<int> candidate(3);
while (num.size() < 1500) {
int candidate = INT_MAX;
for (int i = 0; i < p.size(); i++) {
int t;
while (num.back() >= (t=num[idx[i]] * p[i])) idx[i]++;
candidate = std::min(candidate, t);
}
num.push_back(candidate);
}
auto stop = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stop - start);
std::cout << num.back();
std::cout <<"ntakes "<< duration.count() << " microseconds";
}

代码可以进一步改进。想法是一样的,但通过记住候选数组[3]中的乘法结果,执行的乘法次数减少了:

const vector<int> p{ 2,3,5 };
vector<int> idx{ 1,0,0 };
vector<int> num = { 2,3,4,5 }; num.reserve(1500);
vector<int> candidate{ 6,6,10 };
while (num.size() < 1500) {
auto it = std::min_element(candidate.begin(), candidate.end());
if (num.back() != *it) num.push_back(*it);
int which_p = it - candidate.begin();
*it = num[++idx[which_p]] * p[which_p];
}