丑数三连

丑数三连

最近刷leetcode发现丑数问题十分有意思,涉及到一些数学技巧,正好一起来学习一下。学习完可以去Leetcode上拿下一下三道题。

263.丑数
264.丑数2
313.超级丑数

开始刷题

先介绍一下丑数的定义:(摘自百度百科)

说法一(ugly number):把只包含质因子2,3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但7、14不是,因为它们包含质因子7。 习惯上我们把1当做是第一个丑数。

说法二(humble number):对于一给定的素数集合 S = {p1, p2, …, pK},考虑一个正整数集合,该集合中任一元素的质因数全部属于S。这个正整数集合包括,p1、p1p2、p1p1、p1p2p3…(还有其它)。该集合被称为S集合的“丑数集合”。

263.丑数

很显然263题说的是第一种最简单的丑数。我们可以想到一种最直接的判断方法,按照定义来判断。依次除以2,3,5.

class Solution(object):
	def isUgly(self, num):
		"""
		:type num: int
		:rtype: bool
		"""
		if num ==1:
			return True
		elif num >1:
			while(num>1):
				if num%2 ==0:
					num = num//2
				elif num%3 == 0:
					num = num//3
				elif num%5==0:
					num = num//5
				else:
					return False
			return True

264.丑数II

这道题就厉害一点了,还是按照第一种定义,但人家要问第n个。有了第一题的基础,我感觉就很容易啦,直接简单粗暴的暴力法,一个一个判断是否为丑数,一直数到第n个。快乐的写完代码,提交,结果人家说我超时了,哭唧唧。

很显然不是这么做的,丑数肯定是按照某种规律存在的。如果说我们能够根据之前的丑数直接知道下一个丑数是什么,而不是一个一个判断,那就可以快速算出来第n个。

好消息是丑数只有2,3,5三个质因子。那么我将已经算出来的丑数分别乘上2,3,5.根据定义得到的数字一定是丑数,这就得到一个丑数的集合,那我们就可以在这个集合里面找到下一个丑数了,而且说不定还能找到未来的若干个。

看到这里似乎有点思路了,似乎用递归可以解这个问题。但是这样搞算出来很多肯定是重复的,我们又要去重又要排序,越搞越复杂了。

那么这个时候就要使用强大的多指针技巧啦。在找下一个丑数的时候,我们要保证它一定比现有的大,而且要比后面的小。那么指针怎么用,且细看代码。

我们初始化三个指针分别对应2,3,5.然后循环计算所有丑数。
每一步:
1.在 nums[i2] * 2,nums[i3] * 3 和 nums[i5] * 5 选出最小的数字添加到数组 nums 中。
2.将该数字对应的因子指针向前移动一步。

class Solution(object):
	def nthUglyNumber(self, n):
		"""
		:type n: int
		:rtype: int
		"""
		l = [1]
		p2 = p3 = p5 = 0

		for i in range(1,n):
			ugly = min(l[p2]*2,l[p3]*3,l[p5]*5)
			l.append(ugly)
			if ugly == l[p2]*2:
				p2+=1
			if ugly == l[p3]*3:
				p3+=1
			if ugly == l[p5]*5:
				p5+=1

		return l[-1]

313.超级丑数

这道题就更厉害了,他们把丑数的定义提升到第二个,给定一个质数的数组,然后求第n个丑数。

那我们就将方法升级成n指针,构建一个指针数组,然后按照之前的方法来求。

class Solution(object):
	def nthSuperUglyNumber(self, n, primes):
		"""
		:type n: int
		:type primes: List[int]
		:rtype: int
		"""
		L= [1 for _ in range(n)]
		p = [0 for _ in range(len(primes))]

		for i in range(1,n):
			mini = min(L[p[j]]*primes[j] for j in range(len(primes)))
			L[i] = mini
			for j in range(len(primes)):
				if L[i] == L[p[j]]*primes[j]:
					p[j]+=1
		return L[-1]

总结

至此我们解决了三道丑数问题,重点主要在于从前往后的递推和多指针的使用。其实后面还有一道丑数问题1201.丑数III。这道题方法更复杂一些,感兴趣的可以研究一下,不过我准备以后再讲。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值