【Leetcode】264. Ugly Number II

题目地址:

https://leetcode.com/problems/ugly-number-ii/

一个正整数是丑数,含义是它的素因子只有 2 , 3 , 5 2,3,5 2,3,5。规定 1 1 1是第 1 1 1个丑数,问第 n n n个丑数是几。

思路是多路归并。设丑数集合为 S S S,考虑三个序列: S 2 = [ 2 × 1 , 2 × 2 , 2 × 3 , . . . ] = 2 S S 3 = [ 3 × 1 , 3 × 2 , 3 × 3 , . . . ] = 3 S S 5 = [ 5 × 1 , 5 × 2 , 5 × 3 , . . . ] = 5 S S_2=[2\times 1,2\times 2,2\times 3,...]=2S\\S_3=[3\times 1,3\times 2,3\times 3,...]=3S\\S_5=[5\times 1,5\times 2,5\times 3,...]=5S S2=[2×1,2×2,2×3,...]=2SS3=[3×1,3×2,3×3,...]=3SS5=[5×1,5×2,5×3,...]=5S也就是说, S i S_i Si就是所有含素因子 i i i的丑数。求第 n n n个丑数是几,相当于在求这三个序列里第 n − 1 n-1 n1小的数是几。用三个指针计数即可。由于 S i S_i Si构造的特殊性,我们可以直接将三个指针直接指向我们要构造的序列 S S S。第一个丑数是 1 1 1,可以先令 S [ 0 ] = 1 S[0]=1 S[0]=1,想象有三个指针 i , j , k i,j,k i,j,k都指向 S [ 0 ] S[0] S[0],然后每次看一下 2 × S [ i ] , 3 × S [ j ] , 5 × S [ k ] 2\times S[i],3\times S[j],5\times S[k] 2×S[i],3×S[j],5×S[k]哪个最小,然后append到 S S S后面,将那个最小的数对应的指针后移。需要注意的是,如果某个数丑数被枚举了多次,需要将对应的指针同时后移。例如,容易知道前五项 S = [ 1 , 2 , 3 , 4 , 5 , . . . ] S=[1,2,3,4,5,...] S=[1,2,3,4,5,...],接下来要枚举的丑数是 6 6 6,但是 6 = 2 × 3 = 3 × 2 6=2\times 3=3\times 2 6=2×3=3×2,会同时被 i i i j j j枚举到,枚举一次之后要将两个指针同时后移,避免重复枚举。代码如下:

class Solution {
 public:
  int nthUglyNumber(int n) {
    vector<int> a(n);
    a[0] = 1;
    int idx = 1;
    for (int two = 0, three = 0, five = 0; idx < n;) {
      int ne = min(min(a[two] * 2, a[three] * 3), a[five] * 5);
      a[idx++] = ne;
      if (ne == a[two] * 2) two++;
      if (ne == a[three] * 3) three++;
      if (ne == a[five] * 5) five++;
    }

    return a.back();
  }
};

时空复杂度 O ( n ) O(n) O(n)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值