算法一 Ugly Numbers

一、问题描述
      质因子只有2、3、5的数称为丑数,为了方便,1也被归为丑数(1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15…)
   现给出一个正整数n,求第n个丑数

二、常规解法
难点1. 如何求丑数
       下图是百度百科给出的质因子定义

因为任何正整数都可以写成独一无二的质因子分解式,且丑数的质因子只有2,3,5,所以

任意丑数N = 2^n1 * 3^n2 * 5^n3(n1 >= 0 && n2 >= 0 && n3 >= 0)

除1以外,n1,n2,n3比不全为0,不妨设n1>0,此时

不为1的丑数N = N1 * 2N1 = 2^(n1 - 1) * 3^n2 * 5^n3( (n1-1) >= 0 && n2 >= 0 && n3 >= 0)

有没有发现N1也是个丑数呢?所以除1外的所有丑数都能写成2或者3或者5乘以另一个比他小的丑数。
     所以前N个丑数一定包含下列的集合里

2*N1、2*N2、2*N3、....、2*Nn-1
3*N1、3*N2、3*N3、....、3*Nn-1
5*N1、5*N2、5*N3、....、5*Nn-1
(N1=1,Ni代表第i个丑数,)

然后利用归并,取出这个集合的第n个数。

难点2. 去除重复元素
       这个问题的本质是:我们产生的新丑数必定是当前3个序列中的最小值,其他2序列的丑数必定是大于等于它的关系。(好像没有表达清楚,(⊙o⊙)…)

实现代码

#include <stdio.h>#define N 2000#define min(a,b) ((a)<(b)?(a):(b))  long long int getNthUglyNumber(int n) {// 元素类型是 long long int!long long int uglyNumbers[N] = { 1 };int tail = 1;int indexOf2 = 0;int indexOf3 = 0;int indexOf5 = 0;for (int i = 0; i < n; ++i) {long long int multipleOf2 = uglyNumbers[indexOf2] * 2;long long int multipleOf3 = uglyNumbers[indexOf3] * 3;long long int multipleOf5 = uglyNumbers[indexOf5] * 5;long long int uglyNumber = min(multipleOf2, min(multipleOf3, multipleOf5));if (uglyNumber == multipleOf2) {++indexOf2;}if (uglyNumber == multipleOf3) {++indexOf3;}if (uglyNumber == multipleOf5) {++indexOf5;}uglyNumbers[tail++] = uglyNumber;}return uglyNumbers[n - 1];
}int main() {// int n = 11;// for (int i = 1; i < n; ++i) {//     printf("%d'th ugly number is %d\n", i, getNthUglyNumber(i));// }printf("%d'th ugly number is %d\n", 7, getNthUglyNumber(7));printf("%d'th ugly number is %d\n", 10, getNthUglyNumber(10));printf("%d'th ugly number is %d\n", 15, getNthUglyNumber(15));printf("%d'th ugly number is %d\n", 150, getNthUglyNumber(150));return 0;
}

复杂度分析
1.时间复杂度: O(n)因为只有一个for循环
2.空间复杂度: O(N),因为我们分配了一个N的数组来记录前N个元素
3.LeeCode执行结果

三、拓展解法
      这些解法不一定会比常规解法优秀,但是可能能帮给你开阔思路
思路一、数组法

// 伪代码 这个方法我没有实现
#define N 10000000int getNthUglyNumber(int n) {// Note: 用户空间能否分配如此大的空间?char arr[N] = { 0, 1 };int count = 0;for (int i = 0; i < N; ++i) {if (arr[i] == 0)continue;// Note:2 * i会不会比 N 大?arr[2 * i] = 1;arr[3 * i] = 1;arr[5 * i] = 1;if (++count == n)return i;}
}

这个方法其实是我第一次想出来的,问题很明显,我也标出来了,但是如果你的n很小的时候还是挺好用的,不过空间复杂度很高。

思路二、利用正整数的独一无二质因子分解式和二分查找

#include <iostream>
#include <set>
#include <algorithm>#define N    40
#define LEFT  1
#define RIGHT 21474836647int getUglyNumberCountLessAndEqualThanN(long long int* powerOf2, int size, long long int n) {int count = 0;for (long long int multipleOf5 = 1; multipleOf5 <= n; multipleOf5 *= 5) {for (long long int multipleOf3 = 1; multipleOf3 * multipleOf5 <= n; multipleOf3 *= 3) {count += std::upper_bound(powerOf2, powerOf2 + size, n / (multipleOf5 * multipleOf3)) - powerOf2;}}return count;
}long long int getNthUglyNumber(int n) {long long int powerOf2[N] = { 1 };for (int i = 1; i < N; ++i)powerOf2[i] = powerOf2[i - 1] * 2;long long int possible_result = -1;// N = 2^n1 * 3^n2 * 5^n3long long int left  = LEFT;long long int right = RIGHT;while (left <= right) {long long int midst = (left + right) / 2;if (getUglyNumberCountLessAndEqualThanN(powerOf2, N, midst) < n) {left = midst + 1;} else {// maybe midst is the Nth ugly number.possible_result = midst;right = midst - 1;}}return possible_result;
}int main() {int n = 12;// printf("%d'th ugly number is %d\n", n, getNthUglyNumber(n));for (int i = 1; i < n; ++i) {printf("%d'th ugly number is %d\n", i, getNthUglyNumber(i));}printf("%d'th ugly number is %d\n", 7, getNthUglyNumber(7));printf("%d'th ugly number is %d\n", 10, getNthUglyNumber(10));printf("%d'th ugly number is %d\n", 15, getNthUglyNumber(15));printf("%d'th ugly number is %d\n", 150, getNthUglyNumber(150));
}

这种做法很巧妙,但是不利于n很小的情况。下面贴出LeeCode的执行结果

这个算法时间复杂度就不那么明显了,GeeksForGeeks给出的如下图,二分查找是0(logN),但是计数函数的复杂度咋处理。。

四、参考资料
1.题目连接:
https://leetcode.com/problems/ugly-number-ii/
2.参考资料
https://www.geeksforgeeks.org/ugly-numbers/
3.其他
https://baike.baidu.com/item/%E8%B4%A8%E5%9B%A0%E6%95%B0

Ugly Numbers问题相关推荐

  1. [POJ1338]Ugly Numbers

    [POJ1338]Ugly Numbers 试题描述 Ugly numbers are numbers whose only prime factors are 2, 3 or 5. The sequ ...

  2. poj 1338 Ugly Numbers(丑数模拟)

    转载请注明出处:http://blog.csdn.net/u012860063? viewmode=contents 题目链接:http://poj.org/problem?id=1338 Descr ...

  3. 136 - Ugly Numbers

    Ugly Numbers Ugly numbers are numbers whose only prime factors are 2, 3 or 5. The sequence 1, 2, 3, ...

  4. Poj 1338 Ugly Numbers(数学推导)

    一.题目大意 本题要求写出前1500个仅能被2,3,5整除的数. 二.题解 最初的想法是从1开始检验该数是否只能被2,3,5整除,方法是这样的,对于一个数,如果它能被2整除,就除以2,如果它能被3整除 ...

  5. POJ1338 Ugly Numbers(解法二)【废除!!!】

    本文废除!!! 参考链接:POJ1338 Ugly Numbers[水题] 问题链接:POJ1338 Ugly Numbers.基础级练习题,用C语言编写程序. 题意简述:不能被2.3和5以外的素数整 ...

  6. POJ1338 Ugly Numbers

    问题链接:POJ1338 Ugly Numbers.基础级练习题,用C++语言编写程序. 题意简述:不能被2.3和5以外的素数整除的数称为丑数,找出第1500个丑数. 问题分析:换句话说,丑数的因子只 ...

  7. UVA - 136:Ugly Numbers

    Ugly Numbers 来源:UVA 标签: 参考资料:<算法竞赛入门经典>P120 相似题目: 题目 Ugly numbers are numbers whose only prime ...

  8. 【例题5-7 UVA - 136】Ugly Numbers

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 每个丑数x,都能生成3个丑数2x,3x,5x 则我们以1作为起点. 生成丑数. 每次取出set里面最小的那个数. 然后用它去生成其他 ...

  9. 比紫书优化,14行代码AC——例题 5-7 丑数(Ugly Numbers,UVa 136)——解题报告

    题意: 丑数是一些因子只有2,3,5的数.数列1,2,3,4,5,6,8,9,10,12,15--写出了从小到大的前11个丑数,1属于丑数.现在请你编写程序,找出第1500个丑数是什么. 没有输入 输 ...

最新文章

  1. 你可以恢复模糊的图像吗?
  2. 用html做12进制时钟特效,js+css3实现简单时钟特效
  3. su oracle : 只切换用户,而不切换环境;就是说切到oracle用户后,使用的依旧是root的环境。 su - oracle :同时切换用户和环境
  4. 不允许程序员透露薪资!!!凭啥?
  5. python绘制多个条形图_python – 在Matplotlib中绘制多个直方图 – 颜色或并排条形图...
  6. 随想录(招聘怎样的员工)
  7. 土方计算软件FastTFT V15.1.0更新说明(支持AutoCAD2020平台)
  8. python波形分析_[转载]频谱分析:基于python画出时域频域波形
  9. 心不唤物,物不至,聊聊积极心态重要性
  10. 某东满3000减2020真的有这个劵么
  11. 键盘 部分 按键 ~ 需要长按才能打出来
  12. PS 2019 cc衣服换色+去白边
  13. sh文件加密解密gzexe(Cannot decompress $0)
  14. 基于Python的图片批量转PDF实现
  15. Cocos2d-x 2.0.1 学习tests示例(一)Manual Transformation
  16. android app 清理缓存图片,支付宝APP怎么清理缓存 支付宝安卓版缓存清理方法
  17. 实验1 BP神经网络实验
  18. 传统CD车机面板操作说明
  19. 档案十防环境控制设备之3D可视化管控一体化平台图片鉴赏
  20. Image Printing Program Based on Halftoning

热门文章

  1. Scalable Object Detection using Deep Neural Networks 阅读笔记
  2. 端粒效应《The Telemere Effect》程序员的养生指南(二)情绪、思维模式与健康
  3. db2 improt from coldel0x7c
  4. 软考高项目:项目人力资源管理真题
  5. WGS84坐标系转为西安80坐标系的解决方式
  6. 熊孩子乱敲键盘攻破linux桌面,“熊孩子”乱敲键盘就攻破了 Linux 桌面,大神:17 年前我就警告过你们...
  7. 请叫我程序员!(一)
  8. 外行假装内行,我也来谈谈SAP BAPI和BADI
  9. MySQL导入数据库1118错误解决方案[ERR] 1118 - Row size too large (> 8126). Changing some columns to TEXT or BLOB
  10. mac关闭php,mac强制退出程序的方法有哪些