Ugly Number
来源:互联网 发布:淘宝有多少的店铺 编辑:程序博客网 时间:2024/05/21 22:53
Ugly Number
问题描述:只含有素因子2,3,5的数,称为Ugly Number,并且认为1是Ugly Number。eg. 1,2,3,4,5,6,8,9,10,12,…
问题1
给定一个数num,判断其是否为Ugly Number,是则返回true,否则返回false。
分析:判断这个数是否可以被2或者3或者5整除,并且循环判断,直到结果为1,则则这个数是Ugly Number,返回true,否则返回false。
public boolean isUglyNumber(int m) { if(m <= 0) { return false; } while(m != 1) { if(m % 2 == 0) { m /= 2; } else if(m % 3 == 0) { m /= 3; } else if(m % 5 == 0) { m /= 5; } else { return false; } } return true; }
显然,这个算法的时间复杂度是O(logN)。
问题2
给定一个数n,返回Ugly Number列表的第n个数。Ugly Number列表为1,2,3,4,5,6,8,9,10,12,15,....。eg.
n为1时,返回1;
n为7时,返回8;
n为10时,返回12;
…
题目链接:http://www.lintcode.com/zh-cn/problem/ugly-number-ii/
分析:
方法1:可以使用一个循环,从1开始,判断每一个数是不是Ugly Number,直到得到第n个数。
public int nthUglyNumber(int n) { int sum = 0; int i = 1; while(sum < n) { if(isUglyNumber(i)) { sum++; } i++; } return i - 1; }
显然,这个方法的时间复杂度是O(N*logN)。在lintCode上提交的时候,会发现超过时间限制,所以还需要更好的方法。
方法2:可以换一个思路,我们可以用一个数组,来手动生成一个Ugly Number的列表。就如同Fibonacci数列一样,后边的数字,总是可以由前边的数字得到。
假设A是一个长度为n的int数组,起始的时候A[0]=1,其它元素均为default值0。后边的元素均可以通过A[0]和因子2,3,5相乘来得到。
第一步: A[0]=1;
第二步: 取min(2*A[0], 3*A[0], 5*A[0])即2*A[0]=2作为A[1]。此时,A[0]=1,A[1]=2,则后边的元素可以通过A[0]和A[1]和因子2,3,5相乘来得到;
第三步: 由于在第二步中2*A[0]已经作为了A[1],所以,2的因子的数组下标应该加1,即由A[0]变为A[1],取min(2*A[1], 3*A[0], 5*A[0])即3*A[0]=3作为A[2]。此时,A[0]=1,A[1]=2,A[2]=3。后边的元素可以通过A[0],A[1],A[2]和因子2,3,5相乘来得到;
第四步: 以此类推,A[3]=min(2*A[1], 3*A[1], 5*A[0])=2*A[1]=4;
第五步: A[4]=min(2*A[2], 3*A[1], 5*A[0])=5*A[0]=5;
第六步: A[5]=min(2*A[2], 3*A[1], 5*A[1])=6,注意,此时2*A[2]和3*A[1]的值均为最小值6,所以在下一步中,2和3的因子的数组下标都应该加1,即2*A[3]和3*A[2];
第七步: A[6]=min(2*A[3], 3*A[2], 5*A[1])=2*A[3]=8;
…
以此类推,得到A[n-1]即为题目所求。
public int nthUglyNumber(int n) { if(n <= 0) { return 0; } int [] nums = new int[n]; nums[0] = 1; int index2 = 0, index3 = 0, index5 = 0; for(int i = 1; i < n; i++) { nums[i] = Math.min(2 * nums[index2], Math.min(3 * nums[index3], 5 * nums[index5])); if (nums[i] == 2 * nums[index2]) { index2++; } if (nums[i] == 3 * nums[index3]) { index3++; } if(nums[i] == 5 * nums[index5]) { index5++; } } return nums[n - 1]; }
显然,方法2的时间复杂度为O(N)。
问题3
Super Ugly Number,给定一个素数数组primes和一个正整数n,求使用这个数组构建的Ugly Number的第n个数。这个问题是问题2的一般化,在问题2中,相当与primes是{2,3,5}。
题目链接:http://www.lintcode.com/zh-cn/problem/super-ugly-number/
分析: 与问题2的第二种思路一样,这里使用一个数组来保存下标,相当于上面的index2,index3,index5。
/** * @param n a positive integer * @param primes the given prime list * @return the nth super ugly number */ public int nthSuperUglyNumber(int n, int[] primes) { if(n <= 0) { return 0; } int []nums = new int[n]; int []index = new int[primes.length]; nums[0] = 1; for(int i = 1; i < n; i++) { //find min number as nums[i] int min = primes[0] * nums[index[0]]; for(int j = 1; j < primes.length; j++) { if(primes[j] * nums[index[j]] < min) { min = primes[j] * nums[index[j]]; } } nums[i] = min; //update index for(int j = 0; j < primes.length; j++) { if(min == primes[j] * nums[index[j]]) { index[j]++; } } } return nums[n - 1]; }
假设primes的length为M,显然,这个方法的时间复杂度是O(N*M)。
- ugly number & ugly numberii
- Ugly Number
- ugly number
- Ugly Number
- Ugly Number
- Ugly Number
- Ugly number
- Ugly Number
- ugly number
- Ugly Number
- Ugly Number
- Ugly Number
- Ugly Number
- Ugly Number
- ugly number
- Ugly Number
- Ugly Number
- Ugly Number
- SSL_1532 矩阵乘法
- poj 3207 Ikki's Story IV - Panda's Trick 2-SAT
- Xcode Build Search Paths 设置
- 使用bitmap
- 初学者 Vi 备忘单
- Ugly Number
- 关于Linux 下kill 与 pause的一些小思考
- 拉格朗日乘数
- 基于Zimbra搭建的邮箱服务器
- android—AOSP、AOKP、CM的区别
- 【BZOJ2886】最短路【组合数】
- Android View体系(二)实现View滑动的六种方法
- C++卷积神经网络实例:tiny_cnn代码详解(12)——从CNN中看多态性
- mac 下安装android studio