第 n 个丑数

自己想了两天都没思路啊啊啊啊啊我真是太笨了。看了他的 tag,说是用到了动态规划,于是特意看了算法导论里动态规划的部分。然而只是说了其思想,第一步构建合理的数据结构,第二部以递归的形式求解。可见水无常形,动态规划并不是单纯的公式就可以解决的。那么具体如何处理呢?

第一是,什么时候会用到动态规划,就是这样一种情况:后面的结果来自于前面的结果,而前面的结果又已经被求解后存储。前者意味着它的递归结构,后者有种空间换时间的意味。

明确这个就进入第二个问题,丑数是什么?

除了 1 之外,由且只由 2 3 5 三种素因子构成的数即为丑数。既然素因子只能有 2 3 5,那么后面的丑数必然是通过前面的丑数乘以 2/3/5 得到的。

后面的数由前面的求出,而前面的丑数被求出后又储存在数组中,这两点正是之前提到的递归和空间换时间。

那么新的丑数可能是怎么构成的呢?三种:2 *a/ 3 * b/ 5 * c 因此设置三个标记,分别指示其中 a, b, c 的位置。

其中,最小的数字成为新的丑数。而在其被选为新丑数之后,下一个新丑数必然要比这个数大(废话) 所以要将相应的标记后移,以确保下一个新丑数的三个选择均大于当前最大的丑数。

有了以上说明之后,就可以很好理解一下算法了:

int nthUglyNumber(int n) {
    if (n < 1){
        return 0;
    }

    vector<int> ugliness{1};

    auto index2 = 0;
    auto index3 = 0;
    auto index5 = 0;

    auto saveNewUglyIncreaseIt = [&]
    {
        auto const val2    = ugliness[index2] * 2;
        auto const val3    = ugliness[index3] * 3;
        auto const val5    = ugliness[index5] * 5;
        auto const newUgly = min(val2, min(val3, val5));

        if (newUgly == val2){
            ++index2;
        }
        if (newUgly == val3){
            ++index3;
        }
        if (newUgly == val5){
            ++index5;
        }
        ugliness.push_back(newUgly);
    };

    for (int i = 1; i != n; ++i){
        saveNewUglyIncreaseIt();
    }
    return ugliness.back();
}
时间: 2024-10-03 23:29:12

第 n 个丑数的相关文章

Humble Numbers(丑数) 超详解!

给定一个素数集合 S = { p[1],p[2],...,p[k] },大于 1 且素因子都属于 S 的数我们成为丑数(Humble Numbers or Ugly Numbers),记第 n 大的丑数为 h[n]. 算法 1: 一种最容易想到的方法当然就是从 2 开始一个一个的判断一个数是否为丑数.这种方法的复杂度约为 O( k * h[n]),铁定超时(如果你这样做而没有超时,请跟 tenshi 联系) 算法 2: 看来只有一个一个地主动生成丑数了 : 我最早做这题的时候,用的是一种比较烂的

洛谷P2723 丑数 Humble Numbers [2017年 6月计划 数论07]

P2723 丑数 Humble Numbers 题目背景 对于一给定的素数集合 S = {p1, p2, ..., pK},考虑一个正整数集合,该集合中任一元素的质因数全部属于S.这个正整数集合包括,p1.p1*p2.p1*p1.p1*p2*p3...(还有其 它).该集合被称为S集合的“丑数集合”.注意:我们认为1不是一个丑数. 题目描述 你的工作是对于输入的集合S去寻找“丑数集合”中的第N个“丑数”.所有答案可以用longint(32位整数)存储. 补充:丑数集合中每个数从小到大排列,每个丑

插入排序的优化【不靠谱地讲可以优化到O(nlogn)】 USACO 丑数

首先我们先介绍一下普通的插排,就是我们现在一般写的那种,效率是O(n^2)的. 普通的插排基于的思想就是找位置,然后插入进去,其他在它后面的元素全部后移,下面是普通插排的代码: 1 #include<iostream> 2 #include<fstream> 3 #include<stdio.h> 4 using namespace std; 5 int a[200000]; 6 int p[200000]; 7 8 int main(){ 9 ios::sync_wi

lintcode 中等题:Ugly Numbers 丑数

题目 丑数 设计一个算法,找出只含素因子3,5,7 的第 k 大的数. 符合条件的数如:3,5,7,9,15...... 样例 如果k=4, 返回 9 挑战 要求时间复杂度为O(nlogn)或者O(n) 解题 法一:直接暴力,逐次判断一个数是不是丑数 下面只对其中的奇数判断是否是丑数,加不加奇数都超时. class Solution { /** * @param k: The number k. * @return: The kth prime number as description. */

34 - 丑数

题目描述:http://ac.jobdu.com/problem.php?pid=1214 把只包含因子2.3和5的数称作丑数(Ugly Number).例如6.8都是丑数,但14不是,因为它包含因子7. 习惯上我们把1当做是第一个丑数.求按从小到大的顺序的第N个丑数. 解析: 丑数的定义应该为:质因子只含有2.3.5的数 .1 默认是一个丑数. e.g. 8 = 2*2*2; 18 = 2*3*3 都是丑数 直观想法是: 判断一个数是否是丑数,如果它能被2整除,则一直除以2,同理能被3,5整除

HDU 丑数 - 1058 Humble Numbers

这一题是讲了一个名叫丑数的概念(为啥叫丑数,,). 概念:因子中仅仅包含2.3.5,7的数,称为丑数.但其实我百度网上时,发现正常的丑数应该是因子中仅仅包含2.3.5,不过基本都一样. 我们可以通过不断mod2,3,5,7,直到无法在摸,验证此时是否为1来判断该数是否为丑数,但是这样的方法太过浪费时间,所以介绍一种新的方法,下面方法摘自这里点击打开链接. 根据丑数的定义,丑数应该是另一个丑数乘以2.3,5或者7的结果(1除外).因此我们可以创建一个数组,里面的数字是排好序的丑数.里面的每一个丑数

丑数 uva-136 丑数

代码如下: /*丑数是指不能被2.3.5以外的其他素数整除的数,把丑数从小到大排列起来,结果如下: 1,2,3,4,5,6,8,9,10,12,15... 求出第1500个丑数. */ #include<iostream> #include<vector> #include<queue> #include<set> using namespace std; typedef long long LL; int su[3]={2,3,5}; int main()

NYOJ1097 Ugly Numbers 【丑数】

Ugly Numbers 时间限制:1000 ms  |  内存限制:65535 KB 难度:2 描述 Ugly numbers are numbers whose only prime factors are 2, 3 or 5. The sequence 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, ... shows the first 11 ugly numbers. By convention, 1 is included. Now give you need

poj1338 Ugly Numbers(丑数模拟)

转载请注明出处:http://blog.csdn.net/u012860063?viewmode=contents 题目链接:http://poj.org/problem?id=1338 Description Ugly numbers are numbers whose only prime factors are 2, 3 or 5. The sequence 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, ... shows the first 10 ugly number

编程算法 - 丑数 代码(C)

丑数 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 我们把只包含因子2, 3 和 5的数称作丑数. 求按从小到大的顺序的第5个丑数. 可以设置一个数组包含所需要的丑数, 依次比较乘以2, 乘以3, 乘以5的最小的数, 最后返回结果. 如第5个丑数是5, 如1, 2, 3, 4(2*2), 5均是丑数. 代码: /* * main.cpp * * Created on: 2014.6.12 * Author: Spike */ /*ecli