我正在学习C ++。
我正在寻找hamming numbers(主要除数小于或等于5的数字) 当我输入一个数字 n 时,程序应该输出 n -th汉明数字。
输入以下数字,然后输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ...
1 2 3 4 5 6 8 9 10 12 15 16 18 20 24 ...
查找汉明数字看起来很简单,但增加输入数会以指数方式增加运行时间成本。
如果我输入1000
,则费用几乎超过1
秒,
超过1200
,它几乎花费超过5
秒。
这是我写的代码:
while (th > 1)
{
h++;
x = h;
while (x % 2 == 0)
x /= 2;
while (x % 3 == 0)
x /= 3;
while (x % 5 == 0)
x /= 5;
if (x == 1)
th--;
}
所以我想知道如何更快地找到答案。 这个算法似乎不太好。
提前致谢。
答案 0 :(得分:1)
如果您想检查一个特定号码是否是汉明号码,您的代码是好的。当你想建立一个汉明数字列表时,效率很低。
您可以使用自下而上的方法:从1开始,然后递归地将其乘以2,3和5,以使所有汉明数字达到一定限度。你必须照顾重复,因为你可以通过2·3和3·2达到6。一套可以解决这个问题。
下面的代码将生成适合32位无符号整数的所有汉明数。它通过“传播”到所有汉明数字来填充一组。然后它从集合中构造一个有序向量,您可以使用它来查找某个索引处的汉明数字:
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
typedef unsigned int uint;
const uint umax = 0xffffffff;
void spread(std::set<uint> &hamming, uint n)
{
if (hamming.find(n) == hamming.end()) {
hamming.insert(n);
if (n < umax / 2) spread(hamming, n * 2);
if (n < umax / 3) spread(hamming, n * 3);
if (n < umax / 5) spread(hamming, n * 5);
}
}
int main()
{
std::set<uint> hamming;
spread(hamming, 1);
std::vector<uint> ordered(hamming.begin(), hamming.end());
for (size_t i = 0; i < ordered.size(); i++) {
std::cout << i << ' ' << ordered[i] << '\n';
}
return 0;
}
即使您最终创建的汉明数字超出了您的需要,此代码也比线性方法快。
如果你确定没有两次构建数字,你甚至不需要一套。每个汉明号都可以写成h = 2^n2 + 3^n3 + 5^n5
,所以如果你找到一种方法来迭代这些唯一的,你就完成了:
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
typedef unsigned int uint;
int main()
{
const uint umax = 0xffffffff;
std::vector<uint> hamming;
for (uint k = 1;; k *= 2) {
for (uint l = k;; l *= 3) {
for (uint m = l;; m *= 5) {
hamming.push_back(m);
if (m > umax / 5) break;
}
if (l > umax / 3) break;
}
if (k > umax / 2) break;
}
std::sort(hamming.begin(), hamming.end());
for (size_t i = 0; i < hamming.size(); i++) {
std::cout << i << ' ' << hamming[i] << '\n';
}
return 0;
}
循环的奇怪break
语法是必需的,因为我们必须在溢出之前检查大小。如果保证umax*5
不会溢出,则可以在循环的条件部分写入这些条件。
链接Koshinae发布的代码示例使用了类似的策略,但我很惊讶其中有些策略很长。
答案 1 :(得分:0)
在此link中,您可以找到两种不同的解决方案来找到 n 个汉明数。第二种方法是经过优化的方法,可以在几秒钟内得到结果。
/* Function to get the nth ugly number*/
unsigned getNthUglyNo(unsigned n)
{
unsigned ugly[n]; // To store ugly numbers
unsigned i2 = 0, i3 = 0, i5 = 0;
unsigned next_multiple_of_2 = 2;
unsigned next_multiple_of_3 = 3;
unsigned next_multiple_of_5 = 5;
unsigned next_ugly_no = 1;
ugly[0] = 1;
for (int i=1; i<n; i++)
{
next_ugly_no = min(next_multiple_of_2,
min(next_multiple_of_3,
next_multiple_of_5));
ugly[i] = next_ugly_no;
if (next_ugly_no == next_multiple_of_2)
{
i2 = i2+1;
next_multiple_of_2 = ugly[i2]*2;
}
if (next_ugly_no == next_multiple_of_3)
{
i3 = i3+1;
next_multiple_of_3 = ugly[i3]*3;
}
if (next_ugly_no == next_multiple_of_5)
{
i5 = i5+1;
next_multiple_of_5 = ugly[i5]*5;
}
} /*End of for loop (i=1; i<n; i++) */
return next_ugly_no;
}