编写一个程序,找出第 n
个丑数。
丑数就是只包含质因数 2, 3, 5
的正整数。
剑指OFFER上也有这道题。
思路:
对于某一个丑数来说,它一定是它前面的某个丑数乘以2或3或5得到的,我们要选取 所得到的 所有丑数中最小的一个作为这个位置的新丑数,比如1 2 3 4 5后,6,8,9都是丑数,但要选取6。
一开始的思路是保存前面得到的丑数,然后分别对他们x2,x3,x5,最后从大于i-1位置的丑数中最小的。
这个方法的问题在于多了很多重复计算,比如1x2,1x3,1x5是没必要计算的。
因此:
对某个数来说,它一定是某个位置X2,或另一位置的丑数X3,或另一位置的丑数X5得到的,因此我们使用三个指针p2,p3,p5,p2指向的丑数专门用于X2,p3指向的丑数专门用于X3,p5指向的丑数专门用于X5。这里可能有个疑问,为什么p2指向的位置只能X2不能X3或X5呢,因为p3也是可能指向这个数的,X3我们交由p3去做就好了。
用三个位置的指针相乘得到的最小结果就作为i位置的丑数,得到这个丑数后还要更新p2,p3,p5。这是为了节省计算量,假设现在p2指向的数乘以2作为新位置的丑数,下一次计算新的丑数时,这个p2指向的位置就没必要计算了,因为它乘以2后得到的是i位置的丑数,一定小于i+1位置的丑数,因此我们要更新p2的位置;同时也要与num[p3]*3和num[p5]*5作对比,以6为例,3x2可以得到6,但2x3也可以得到6,因此还要与p3和p5的结果做比较,如果相等则同步也要更新p3与p5的指向。
class Solution { public: int GetUglyNumber_Solution(int index) { vector<int> ans(index); ans[0]=1; int p2=0,p3=0,p5=0; for(int i=1;i<index;i++) { ans[i]=min(ans[p2]*2,min(ans[p3]*3,ans[p5]*5)); if(ans[i]==ans[p2]*2) p2++; if(ans[i]==ans[p3]*3) p3++; if(ans[i]==ans[p5]*5) p5++; } return ans.back(); } };