动态规划法解第n个丑数问题

丑数是唯一素数为2、3或5的数。序列1、2、3、4、5、6、8、9、10、12、15…显示前11个丑数。按照惯例,其中包括1。
给定数字n,任务是查找第n个丑数。

输入:n = 7
输出8

输入:n = 10
输出:12

输入:n = 15
输出:24

输入:n = 150
输出:5832

方法1(简单)
对所有正整数循环,直到一个丑陋的数字小于n(如果一个整数丑陋而不是递增的丑陋数字计数)。
要检查数字是否丑陋,请将该数字除以2、3和5的最大可除幂。如果数字变为1,则它是丑陋的数字,否则不是。

例如,让我们看看如何检查300是否丑陋。2的最大可乘幂是4,将300除以4后得到75。3的最大可乘幂是3,将75除以3后得到25。5的最大可乘幂是25,将25除以25后得到1由于我们最终得到1,所以300是丑数。

下面是上述方法的实现:

# Python3 code to find nth ugly number

# This function divides a by greatest
# divisible power of b


def maxDivide(a, b):
	while a % b == 0:
		a = a / b
	return a

# Function to check if a number
# is ugly or not
def isUgly(no):
	no = maxDivide(no, 2)
	no = maxDivide(no, 3)
	no = maxDivide(no, 5)
	return 1 if no == 1 else 0

# Function to get the nth ugly number
def getNthUglyNo(n):
	i = 1
	
	# ugly number count
	count = 1

	# Check for all integers untill
	# ugly count becomes n
	while n > count:
		i += 1
		if isUgly(i):
			count += 1
	return i


# Driver code
no = getNthUglyNo(150)
print("150th ugly no. is ", no)

Output

150th ugly no. is 5832

此方法效率不高,因为它会检查所有整数,直到丑陋的数字计数变为n.
方法2(使用动态规划)
这是具有O(n)额外空间的省时解决方案。丑数序列是1、2、3、4、5、6、8、9、10、12、15…,
因为每个数字只能除以2、3、5,这是查看序列的一种方法将序列分为以下三组:
(1)1×2、2×2、3×2、4×2、5×2,…
(2)1×3、2×3、3×3, 4×3、5×3,…
(3)1×5、2×5、3×5、4×5、5×5,…
我们可以发现每个子序列都是丑序列本身(1、2、3、4、5,…)乘以2、3、5。然后我们使用类似的合并方法作为合并排序,从三个序列中获取每个丑数子序列。每一步我们都选择最小的一步,然后再向前迈一步。

1 Declare an array for ugly numbers:  ugly[n]
2 Initialize first ugly no:  ugly[0] = 1
3 Initialize three array index variables i2, i3, i5 to point to 
   1st element of the ugly array: 
        i2 = i3 = i5 =0; 
4 Initialize 3 choices for the next ugly no:
         next_mulitple_of_2 = ugly[i2]*2;
         next_mulitple_of_3 = ugly[i3]*3
         next_mulitple_of_5 = ugly[i5]*5;
5 Now go in a loop to fill all ugly numbers till 150:
For (i = 1; i < 150; i++ ) 
{
    /* These small steps are not optimized for good 
      readability. Will optimize them in C program */
    next_ugly_no  = Min(next_mulitple_of_2,
                        next_mulitple_of_3,
                        next_mulitple_of_5); 

    ugly[i] =  next_ugly_no       

    if (next_ugly_no  == next_mulitple_of_2) 
    {             
        i2 = i2 + 1;        
        next_mulitple_of_2 = ugly[i2]*2;
    } 
    if (next_ugly_no  == next_mulitple_of_3) 
    {             
        i3 = i3 + 1;        
        next_mulitple_of_3 = ugly[i3]*3;
     }            
     if (next_ugly_no  == next_mulitple_of_5)
     {    
        i5 = i5 + 1;        
        next_mulitple_of_5 = ugly[i5]*5;
     } 
     
}/* end of for loop */ 
6.return next_ugly_no

Example:

initialize
   ugly[] =  | 1 |
   i2 =  i3 = i5 = 0;

First iteration
   ugly[1] = Min(ugly[i2]*2, ugly[i3]*3, ugly[i5]*5)
            = Min(2, 3, 5)
            = 2
   ugly[] =  | 1 | 2 |
   i2 = 1,  i3 = i5 = 0  (i2 got incremented ) 

Second iteration
    ugly[2] = Min(ugly[i2]*2, ugly[i3]*3, ugly[i5]*5)
             = Min(4, 3, 5)
             = 3
    ugly[] =  | 1 | 2 | 3 |
    i2 = 1,  i3 =  1, i5 = 0  (i3 got incremented ) 

Third iteration
    ugly[3] = Min(ugly[i2]*2, ugly[i3]*3, ugly[i5]*5)
             = Min(4, 6, 5)
             = 4
    ugly[] =  | 1 | 2 | 3 |  4 |
    i2 = 2,  i3 =  1, i5 = 0  (i2 got incremented )

Fourth iteration
    ugly[4] = Min(ugly[i2]*2, ugly[i3]*3, ugly[i5]*5)
              = Min(6, 6, 5)
              = 5
    ugly[] =  | 1 | 2 | 3 |  4 | 5 |
    i2 = 2,  i3 =  1, i5 = 1  (i5 got incremented )

Fifth iteration
    ugly[4] = Min(ugly[i2]*2, ugly[i3]*3, ugly[i5]*5)
              = Min(6, 6, 10)
              = 6
    ugly[] =  | 1 | 2 | 3 |  4 | 5 | 6 |
    i2 = 3,  i3 =  2, i5 = 1  (i2 and i3 got incremented )

Will continue same way till I < 150
# Python program to find n'th Ugly number

# Function to get the nth ugly number


def getNthUglyNo(n):

	ugly = [0] * n # To store ugly numbers

	# 1 is the first ugly number
	ugly[0] = 1

	# i2, i3, i5 will indicate indices for
	# 2,3,5 respectively
	i2 = i3 = i5 = 0

	# Set initial multiple value
	next_multiple_of_2 = 2
	next_multiple_of_3 = 3
	next_multiple_of_5 = 5

	# Start loop to find value from 
	# ugly[1] to ugly[n]
	for l in range(1, n):

		# Shoose the min value of all 
		# available multiples
		ugly[l] = min(next_multiple_of_2,
					next_multiple_of_3, 
					next_multiple_of_5)

		# Increment the value of index accordingly
		if ugly[l] == next_multiple_of_2:
			i2 += 1
			next_multiple_of_2 = ugly[i2] * 2

		if ugly[l] == next_multiple_of_3:
			i3 += 1
			next_multiple_of_3 = ugly[i3] * 3

		if ugly[l] == next_multiple_of_5:
			i5 += 1
			next_multiple_of_5 = ugly[i5] * 5

	# Return ugly[n] value
	return ugly[-1]

# Driver Code
def main():

	n = 150

	print getNthUglyNo(n)


if __name__ == '__main__':
	main()



Output

5832

此题的关键是找到丑数的规律。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值