Bootstrap

LeetCode —— 丑数

263.丑数

请添加图片描述

如果因数包含指定质因数,就说明能被该质因数整除。

那我们就不断去除它的这几个质因数,如果已经不含它指定的质因数了且当前数值不为一,那么就不是丑数。否则为丑数

class Solution {
    public boolean isUgly(int n) {
        //非正数
        if(n <= 0){
            return false;
        }
        //一直除指定的质因数
        while(n != 1){
            //用来检测是否还能继续除指定质因数了
            int temp = n;
            //当前包含因数2
            while(n % 2 == 0){
                n >>= 1;
            }
            //当前包含因数3
            while(n % 3 == 0){
                n /= 3;
            }
            //当前包含因数5
            while(n % 5 == 0){
                n /= 5;
            }
            //已经不能被2或3或5整除了
            if(n == temp){
                return false;
            }
        }

        return true;
    }
}

请添加图片描述



264.丑数 ||

请添加图片描述

采用了哈希表去重,优先队列(小根堆)去不断存储并更新最小的丑数

class Solution {
    public int nthUglyNumber(int n) {
        //记录丑数
        int urgy = 0;
        //记录质因子
        int [] arr = {2, 3, 5};
        //优先队列存储所有丑数并自动排序
        Queue<Long> queue = new PriorityQueue<Long>();
        //用哈希表去重
        Set set = new HashSet();
        //初始化
        queue.add(1L);
        set.add(1L);
        //循环寻找第N个丑数
        for(int i = 0; i < n; i++){
            //获取当前丑数
            long curr = queue.poll();
            urgy = (int)curr;            
            //基于当前丑数产生新丑数
            for(int num : arr){
                if(set.add(curr * num)){
                    queue.add(curr * num);
                }                
            }
        }
        //返回结果
        return urgy;
    }
}

这种方法比较耗时,新方法采用了动态规划三指针法,因为新丑数都是基于已经确定的原丑数得出来的,所以我们把原丑数想象为三组,分别与指定的质因数相乘,谁最小就将当前丑数定为谁,再将对应指针移动到下一位。【此处引用一个大佬的思路帮助理解,因为是评论就没给出原文链接】

请添加图片描述

class Solution {
    public int nthUglyNumber(int n) {
        //三指针法
        int [] idx = {0, 0, 0};
        //保存丑数
        int [] urgy = new int[n];
        //初始化
        urgy[0] = 1;
        //循环构造最小丑数
        for(int i = 1; i < n; i++){
            //原来的丑数分别与2、3、5相乘
            int num1 = urgy[idx[0]] * 2;
            int num2 = urgy[idx[1]] * 3;
            int num3 = urgy[idx[2]] * 5;
            //取最小值
            int min_num = Math.min(num1, Math.min(num2, num3));
            urgy[i] = min_num;
            //将对应idx移动到下一位
            if(min_num == num1){
                idx[0]++;
            }
            if(min_num == num2){
                idx[1]++;
            }
            if(min_num == num3){
                idx[2]++;
            }
        }
        //返回结果
        return urgy[n - 1];
    }
}

请添加图片描述

;