如何在给定质因数但指数未知的情况下生成数字?
我想知道如何以快速而优雅的方式解决这个问题:
我们将每个数字n定义为“丑陋”,这些数字可以写成以下形式:2^x * 3^y * 5^z;,其中x、y和z是自然数。找到第 1500 个丑数。
例如,第一个“丑陋”的数字是:
1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, ...
我尝试使用暴力来解决这个问题,以这种方式:
import itertools as it
def is_ugly(n):
'''Return `True` if *n* is an ugly number.'''
if n == 1:
return True
while not n % 2:
n //= 2
while not n % 3:
n //= 3
while not n % 5:
n //= 5
return n == 1
def nth_ugly(n):
'''Return the nth ugly number.'''
num = 0
for i in it.count(1):
if is_ugly(i):
num += 1
if num == n:
return i
但这需要相当多的时间,我想找到一个更快更好的解决方案。
我知道丑数的素因数,但我想不出一种方法可以按照正确的顺序生成这些数字。
我认为必须有一种方法可以生成这些数字,而不必检查所有数字。问题在于,素因数的指数似乎是相当随机分布的。
看这个表:
n |number| x | y | z |
------------------------
1 | 1 | 0 | 0 | 0 |
------------------------
2 | 2 | 1 | 0 | 0 |
------------------------
3 | 3 | 0 | 1 | 0 |
------------------------
4 | 4 | 2 | 0 | 0 |
------------------------
5 | 5 | 0 | 0 | 1 |
------------------------
6 | 6 | 1 | 1 | 0 |
------------------------
7 | 8 | 3 | 0 | 0 |
------------------------
8 | 9 | 0 | 2 | 0 |
------------------------
9 | 10 | 1 | 0 | 1 |
------------------------
10 | 12 | 2 | 1 | 0 |
------------------------
11 | 15 | 0 | 1 | 1 |
------------------------
12 | 16 | 4 | 0 | 0 |
------------------------
13 | 18 | 1 | 2 | 0 |
------------------------
14 | 20 | 2 | 0 | 1 |
------------------------
15 | 24 | 3 | 1 | 0 |
------------------------
正如您所看到的,x、y 和 z 值似乎不遵循任何规则。
你们中有人能找到解决这个问题的方法吗?
我正在考虑尝试将问题分为不同的部分。 由于问题是由指数的随机性决定的,我可以尝试独立生成 2s、3s、5s 的幂,然后生成 2^x*3^y、2^x*5^z 等形式的数字。 最后把它们放在一起,但我不知道这是否能解决我的问题。
Possible Duplicates:
nth ugly number
Find the Kth least number for expression (2^x)*(3^y)*(5^z)
I'm wondering how to solve this problem in a fast and elegant way:
We define "ugly" every number n which can be written in the form: 2^x * 3^y * 5^z;, where x,y and z are natural numbers. Find the 1500th ugly number.
E.g. the first "ugly" numbers are:
1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, ...
I've tried to solve this problem using brute-force, in this way:
import itertools as it
def is_ugly(n):
'''Return `True` if *n* is an ugly number.'''
if n == 1:
return True
while not n % 2:
n //= 2
while not n % 3:
n //= 3
while not n % 5:
n //= 5
return n == 1
def nth_ugly(n):
'''Return the nth ugly number.'''
num = 0
for i in it.count(1):
if is_ugly(i):
num += 1
if num == n:
return i
But it takes quite a lot of time, and I'd like to find a faster and better solution.
I know the prime factors of ugly numbers, but I can't think of a way to generate these numbers following the correct order.
I think there must be a way to generate these numbers without having to check all the numbers. The problem is that it seems like exponents of the prime factors are distributed quite randomly.
Look at this table:
n |number| x | y | z |
------------------------
1 | 1 | 0 | 0 | 0 |
------------------------
2 | 2 | 1 | 0 | 0 |
------------------------
3 | 3 | 0 | 1 | 0 |
------------------------
4 | 4 | 2 | 0 | 0 |
------------------------
5 | 5 | 0 | 0 | 1 |
------------------------
6 | 6 | 1 | 1 | 0 |
------------------------
7 | 8 | 3 | 0 | 0 |
------------------------
8 | 9 | 0 | 2 | 0 |
------------------------
9 | 10 | 1 | 0 | 1 |
------------------------
10 | 12 | 2 | 1 | 0 |
------------------------
11 | 15 | 0 | 1 | 1 |
------------------------
12 | 16 | 4 | 0 | 0 |
------------------------
13 | 18 | 1 | 2 | 0 |
------------------------
14 | 20 | 2 | 0 | 1 |
------------------------
15 | 24 | 3 | 1 | 0 |
------------------------
As you can see x,y and z values don't seem to follow any rule.
Can someone of you find any solution to this problem?
I'm thinking of trying to divide the problem in different parts.
Since the problem is determined by the randomness of exponents, I could try to generate independently the powers of 2s,3s,5s and then the numbers of the form 2^x*3^y,2^x*5^z etc.
And finally put them together, but I don't know if this will solve my issue.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这是一个完整的解决方案。 O(n) 复杂度,它按顺序生成每个数字一次。
Here is a complete solution. O(n) complexity, it generates every number once and in order.
这是使用堆的解决方案。我们的想法是,我们跟踪指数以及丑陋的产品。对于每次迭代,算法最多执行 3 个 find_min 操作和 3 个插入操作。 find_min 可能是多余的,因为您可以通过对任何指数加 1 来获得每个操作,并且有 3 个指数。我们执行三次插入,因为我们为每个指数加一并将其插入到堆中。为了找到第 n 个丑数,我们必须执行 N 个操作,即 6 * O(log n),因此该算法的时间复杂度为 O(n log n)。堆本身因为每次迭代只能增长恒定量,所以是 SPACE(O(n))
Here's a solution using a heap. The idea is that we keep track of the exponents along with the ugly product. For each iteration, the algorithm performs up to 3 find_min operations and 3 insert operations, The find_mins can be redundant because you can get to each by adding one to any exponent, and there are three exponents. We do an insert three times because we add one to each exponent and insert that into the heap. To find the nth ugly number, we thus have to perform N operations that are 6 * O(log n), thus the algorithm has time complexity of O(n log n). The heap itself, since it can only grow by a constant amount for each iteration, is SPACE(O(n))
使用一个列表(下面代码中的n)来存储所有前一个丑数,下一个丑数是(n*2,n*3,n*5)中大于n[-1]的最小数:
这是一个 O(n^2) 解决方案,因此不要尝试大数字。
use a list (n in the following code) to store all the prev ugly numbers, the next ugly number is the min number of (n*2, n*3, n*5) that is larger then n[-1]:
It's a O(n^2) solution, so don't try large number.
我建议你逐步解决这个问题,并将你找到的所有难看的数字存储在一个列表中。
当检查一个数字是否丑陋时,你只需要检查它是否是你的数字之一乘以 2、3 或 5。
编辑:我只是尝试像这样实现,
但这种方法毫无希望地停滞不前。太天真了。 :) 而是使用某种埃拉托斯特尼筛法。
I suggest you solve this incrementally and store all the ugly numbers you find in a list.
When checking a number for ugliness then, you only have to check whether it's one of your number times 2, 3 or 5.
EDIT: I just tried to implement that like this
but this approach stagnates hopelessly. Too naive. :) Use some sort of Sieve of Eratosthenes rather.