这是剑指第一次卡死我的题……记录一下

首先看题目:

把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。

一开始的思路:

一开始,我就直接蛮力,就按照它的描述,从2到根号n一个个试,看看是不是它的因子,是的话是不是质数,是质数的话是不是2或者3或者5什么的。

最后做出来,前面几个数字都是可以通过测试的,但提交就一直说我超时通过率为0……然后本地测了下超时的用例1500——emmm确实是,算了半天都没出来。

然后百度,百度百科上对丑数的判别:

首先除2,直到不能整除为止,然后除5到不能整除为止,然后除3直到不能整除为止。最终判断剩余的数字是否为1,如果是1则为丑数,否则不是丑数。
用这个思路又写了个,从2开始往上+1,然后每个都这样判断是不是丑数,好的还是超时。(其实这个和我的蛮力一样,只是我的蛮力比较恶心。)
最后没办法看讨论,大多用的都是一个思路:
所有的丑数都是前面的那个丑数乘以2或者3或者5而来的。所以我们可以维护三个队列和一个正式丑数序列:
链接:https://www.nowcoder.com/questionTerminal/6aa9e04fc3794f68acf8778237ba065b
来源:牛客网

(1)丑数数组: 1
乘以2的队列:2
乘以3的队列:3
乘以5的队列:5
选择三个队列头最小的数2加入丑数数组,同时将该最小的数乘以2,3,5放入三个队列;
(2)丑数数组:1,2
乘以2的队列:4
乘以3的队列:3,6
乘以5的队列:5,10
选择三个队列头最小的数3加入丑数数组,同时将该最小的数乘以2,3,5放入三个队列;
(3)丑数数组:1,2,3
乘以2的队列:4,6
乘以3的队列:6,9
乘以5的队列:5,10,15
选择三个队列头里最小的数4加入丑数数组,同时将该最小的数乘以2,3,5放入三个队列;
(4)丑数数组:1,2,3,4
乘以2的队列:6,8
乘以3的队列:6,9,12
乘以5的队列:5,10,15,20
选择三个队列头里最小的数5加入丑数数组,同时将该最小的数乘以2,3,5放入三个队列;
(5)丑数数组:1,2,3,4,5
乘以2的队列:6,8,10,
乘以3的队列:6,9,12,15
乘以5的队列:10,15,20,25
选择三个队列头里最小的数6加入丑数数组,但我们发现,有两个队列头都为6,所以我们弹出两个队列头,同时将12,18,30放入三个队列;

然后我按照这个思路,自己实现了次,也遇到了很多问题……

我是真正地维护了三个队列,然后每次把最新的丑数乘以2,3,5然后分别加到三个队列中,然后取出最小的数字处理,从哪个队列中取出就哪个队列出队。队列直接用PriorityQueue,可以直接获得最小值。

遇到的问题是:

  1. 我这个直接按照上面的思路做的话,到后面数字很大会溢出……然后溢出的话,比如一个很大的丑数*5溢出了,就变成一个负数然后以后的最小值就是这个负数了——我的解决方法是:重写一个Compator,然后传入PriorityQueue中去。

  2. 这还不够,因为到了后面,可能出现一个队列中的所有数字都小于0的情况,所以在拿出数字后比较出最小的这一步也要考虑到负数的情况。

看下我的这个思路的实现的代码,已经通过测试:

import java.util.*;public class Solution {public int GetUglyNumber_Solution(int index) {if(index <= 0)return 0;if(index == 1)return 1;Queue<Integer> q2 = new PriorityQueue<Integer>(new NewComparator());Queue<Integer> q3 = new PriorityQueue<Integer>(new NewComparator());Queue<Integer> q5 = new PriorityQueue<Integer>(new NewComparator());int uglyNum = 1, count = 1, minTemp;while(true) {q2.add(uglyNum * 2);q3.add(uglyNum * 3);q5.add(uglyNum * 5);//下面的操作这么麻烦是因为会有几个队列有着同样的最小值的情况,这时候都要让它出队minTemp = getMinOfThree(q2.peek(), q3.peek(), q5.peek(), count);if(q2.peek() == minTemp)q2.poll();if(q3.peek() == minTemp)q3.poll();if(q5.peek() == minTemp)q5.poll();uglyNum = minTemp;count++;if(count == index)return uglyNum;}}// 找三个数字中没有溢出的最小值private int getMinOfThree(int a, int b, int c, int count) {if (a < 0 || b < 0 || c < 0) {// 存在溢出情况,有元素小于0int[] temp = new int[3];temp[0] = a;temp[1] = b;temp[2] = c;Arrays.sort(temp);for (int x : temp) {if (x < 0)continue;return x;}}return a < b ? (a < c ? a : c) : (b < c ? b : c);}//因为之前的那个,如果有数字溢出了,就会变成负数,负数肯定最小然后就会被poll出来,最后结果就会有错误private class NewComparator implements Comparator<Integer> {@Overridepublic int compare(Integer o1, Integer o2) {// TODO Auto-generated method stubif(o1 < 0)return 1;if(o1 < o2)return -1;else if(o1 == o2)return 0;else return 1;}}}

但其实我们可以不用维护三个队列:

链接:https://www.nowcoder.com/questionTerminal/6aa9e04fc3794f68acf8778237ba065b
来源:牛客网

们没有必要维护三个队列,只需要记录三个指针显示到达哪一步;“|”表示指针,arr表示丑数数组;
(1)1
|2
|3
|5
目前指针指向0,0,0,队列头arr[0] * 2 = 2,  arr[0] * 3 = 3,  arr[0] * 5 = 5
(2)1 2
2 |4
|3 6
|5 10
目前指针指向1,0,0,队列头arr[1] * 2 = 4,  arr[0] * 3 = 3, arr[0] * 5 = 5
(3)1 2 3
2| 4 6
3 |6 9
|5 10 15
目前指针指向1,1,0,队列头arr[1] * 2 = 4,  arr[1] * 3 = 6, arr[0] * 5 = 5
 
上一个简化后不用维护三个队列的Java的实现代码:
public int GetUglyNumber_Solution2(int index) {if (index <= 0)return 0;ArrayList<Integer> list = new ArrayList<Integer>();// add进第一个丑数1list.add(1);// 三个下标用于记录丑数的位置int i2 = 0, i3 = 0, i5 = 0;while (list.size() < index) {// 三个数都是可能的丑数,取最小的放进丑数数组里面int n2 = list.get(i2) * 2;int n3 = list.get(i3) * 3;int n5 = list.get(i5) * 5;int min = Math.min(n2, Math.min(n3, n5));list.add(min);if (min == n2)i2++;if (min == n3)i3++;if (min == n5)i5++;}return list.get(list.size() - 1);}

可以看见,就是三个指针在动。而且这里似乎不会出现溢出有负数的情况,因为我那里每次是用最新的丑数去乘2,3,5;而这里是用之前的丑数,就i2,i3,i5指针所在的那个丑数来乘,所以好很多。

转载于:https://www.cnblogs.com/wangshen31/p/10649245.html

剑指Offer丑数问题相关推荐

  1. 剑指offer—丑数

    题目描述 把只包含因子2.3和5的数称作丑数(Ugly Number).例如6.8都是丑数,但14不是,因为它包含因子7. 习惯上我们把1当做是第一个丑数.求按从小到大的顺序的第N个丑数. publi ...

  2. 剑指offer——丑数

    题目描述 把只包含质因子2.3和5的数称作丑数(Ugly Number).例如6.8都是丑数,但14不是,因为它包含质因子7. 习惯上我们把1当做是第一个丑数.求按从小到大的顺序的第N个丑数. 思路: ...

  3. 剑指Offer49—丑数

    剑指Offer49-丑数 题意 我们把只包含质因子 2.3 和 5 的数称作丑数(Ugly Number).求按从小到大的顺序的第 n 个丑数. 丑数即只能被 2.3.5 整除.判断一个数是不是丑数的 ...

  4. 【前端js】实现剑指offer|leetcode(二)——数组题目集合

    文章目录 一.数组去重 1. 对排序数组去重(leetcode 26. 删除排序数组中的重复项) 2. 检查是否存在重复元素(leetcode 217. 存在重复元素) 3. 检查相邻k个元素是否存在 ...

  5. 剑指offer:丑数

    题目描述 把只包含质因子2.3和5的数称作丑数(Ugly Number).例如6.8都是丑数,但14不是,因为它包含质因子7. 习惯上我们把1当做是第一个丑数.求按从小到大的顺序的第N个丑数. 解题思 ...

  6. 【剑指offer】丑数

    把只包含因子2.3和5的数称作丑数(Ugly Number).例如6.8都是丑数,但14不是,因为它包含因子7. 习惯上我们把1当做是第一个丑数.求按从小到大的顺序的第N个丑数. leetcode上也 ...

  7. 《剑指offer》-- 把数组排成最小的数、丑数、二进制中1的个数、表示数值的字符串、替换空格

    一.把数组排成最小的数: 1.题目: 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个.例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为 ...

  8. 【LeetCode】剑指 Offer 49. 丑数

    [LeetCode]剑指 Offer 49. 丑数 文章目录 [LeetCode]剑指 Offer 49. 丑数 package offer;public class Solution49 {publ ...

  9. 剑指offer——面试题34:丑数

    剑指offer--面试题34:丑数 Solution1: 最容易想到的,也是最不可能AC的 class Solution {public:int GetUglyNumber_Solution(int ...

最新文章

  1. Oracle存储过程返回游标实例详解
  2. MySQL:数据库优化,看这篇就够了
  3. class反编译成java_Spring Tools Suite(STS)安装反编译插件
  4. struts2静态方法和动态方法调用
  5. java 数据类型model_如何在角度2中使用类数据类型的ngModel?
  6. Python菜鸟入门:day08函数概念
  7. MATLAB常用的基本数学函数
  8. 边相关扫描线填充算法
  9. chrome vue 未响应_分享几个宝藏级Vue管理后台框架 必须收藏
  10. 软件测试简历写成这样,还怕HR不招你?
  11. 使用 VBRichClient 库
  12. 机器学习实战(Machine Learning in Action)学习笔记————05.Logistic回归
  13. Nacos启动报错解决:which: no javac in (/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin)
  14. gromacs ngmx_GROMACS使用教程
  15. mysql产品分类_MySQL习题1 一对多实例 产品和分类
  16. 博弈论——序论(读书笔记)
  17. UnionPay-银联支付-netcore(二)
  18. 银河麒麟服务器系统ip可ping通,但是tongweb的默认端口9060、8088不能访问,访问提示404
  19. mat 释放_Opencv - 释放内存将cv :: Mat引用计数器更改为零
  20. 混沌映射与动态学习的自适应樽海鞘群算法-附代码

热门文章

  1. vscode ---- 插件
  2. php接收get数组数据,php-如何从wordpress数据库中获取数组值get_results
  3. djano 字段不重复_硬不硬你说了算!近 40 张图解被问千百遍的 TCP 3 次握手和 4 次挥手面试题...
  4. JTS Geometry关系判断和分析
  5. rabbitmq如何清空queue队列数据
  6. SpringBoot配置文件映射到JavaBean
  7. ORACLE:索引中丢失IN或OUT参数
  8. RabbitMQ中basicConsume、basicCancel、basicPublish方法
  9. Kotlin入门(12)类的概貌与构造
  10. 2019的第一工作日