【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枚举到,枚举一次之后要将两个指针同时后移,避免重复枚举。代码如下:

public class Solution {
    public int nthUglyNumber(int n) {
        int[] nums = new int[n];
        int idx = 1;
        nums[0] = 1;
        
        for (int two = 0, three = 0, five = 0; idx < n; ) {
            int next = Math.min(nums[two] * 2, Math.min(nums[three] * 3, nums[five] * 5));
            nums[idx++] = next;
            // 如果next这个数可以被2枚举到,就将two后移。
            if (next / 2 == nums[two]) {
                two++;
            }
            // 同上
            if (next / 3 == nums[three]) {
                three++;
            }
            if (next / 5 == nums[five]) {
                five++;
            }
        }
        
        return nums[n - 1];
    }
}

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

©️2020 CSDN 皮肤主题: 创作都市 设计师:CSDN官方博客 返回首页