醜數問題及變種小結
聲明
文章均爲本人技術筆記,轉載請註明出處:
[1] https://segmentfault.com/u/yzwall
[2] blog.csdn.net/j_dark/
1 判斷醜數
因子只包含2,3,5的數稱爲醜數(Ugly Number),習慣上把1當做第一個醜數
- lintcode 517 ugly number
- 劍指offer 面試題34 醜數
解法:參考劍指offer,將待判斷目標依次連續整除2,3,5,如果最後得到1,證明該數爲醜數;
/**
* 依次整除2,3,5判斷(2,3,5順序判斷時間最優)
* http://www.lintcode.com/zh-cn/problem/ugly-number/
* 題意:判斷一個數是否是醜數
* @author yzwall
*/
class Solution {
public boolean isUgly(int num) {
if (num == 0) {
return false;
}
if (num == 1) {
return true;
}
while (num % 2 == 0) {
num /= 2;
}
while (num % 3 == 0) {
num /= 3;
}
while (num % 5 == 0) {
num /= 5;
}
return num == 1 ? true : false;
}
}
2 找出第k大丑數
- lintcode 4 ugly number ii
- 劍指offer 面試題34 醜數拓展
醜數推論
根據醜數定義,有推論如下:
任取一個醜數
1.
2. 如果
2.1 解法1:O(nlogn) 時間複雜度
通過醜數推論,用優先隊列PriorityQueue<T>
的隊首保存當前第HashSet<T>
保證優先隊列中沒有重複醜數;
/**
* 題意:求第n個醜數
* http://www.lintcode.com/zh-cn/problem/ugly-number-ii/
* 解法1:優先隊列+HashSet求解,時間複雜度O(nlogn)
* @author yzwall
*/
class Solution13 {
public int nthUglyNumber(int n) {
PriorityQueue<Long> pq = new PriorityQueue<>(n, new Comparator<Long>(){
public int compare(Long o1, Long o2) {
return o1 < o2 ? -1 : 1;
}
});
HashSet<Long> hash = new HashSet<>();
hash.add(1L);
pq.offer(1L);
int[] primes = new int[]{2, 3, 5};
for (int prime : primes) {
hash.add((long)prime);
pq.offer((long)prime);
}
long min = primes[0];
for (int i = 0; i < n; i++) {
// min始終爲第i+1個醜數,優先隊列提供保證
min = pq.poll();
for (int prime : primes) {
if (!hash.contains(min * prime)) {
hash.add(min * prime);
// HashSet保證優先隊列中無重複醜數
pq.offer(min * prime);
}
}
}
return (int)min;
}
}
2.2 解法2:O(n) 時間複雜度
根據醜數推論,與解法2.1相比,
1. 對於當前第
2. 用數組保存生成的醜數,避免使用優先隊列和哈希表,時間複雜度優化到
代碼部分參考劍指offer 面試題34 醜數拓展
3 找出第k大自定義醜數
自定義醜數的定義是正整數並且所有的質數因子都在所給定的一個大小爲 k 的質數集合內。
比如指定質數集合爲[2, 7, 13, 19]
, 那麼[1, 2, 4, 7, 8, 13, 14, 16, 19, 26, 28, 32]
是前12個超級醜數
自定義醜數是廣義化的醜數,醜數的質數集合指定爲[2, 3, 5]
- lintcode 518 siper ugly number
3.1 解法1:O(nlogn) 時間複雜度
醜數推論,可推廣至自定義醜數:
任取一個自定義醜數
1.
2. 如果
通過上述推論,用優先隊列PriorityQueue<T>
的隊首保存當前第HashSet<T>
保證優先隊列中沒有重複自定義醜數;
/**
* 題意:求第n個自定義醜數
* http://www.lintcode.com/zh-cn/problem/super-ugly-number/
* 解法1:優先隊列+HashSet求解,時間複雜度O(nlogn),空間複雜度O(n)
* @author yzwall
*/
class Solution {
public int nthSuperUglyNumber(int n, int[] primes) {
PriorityQueue<Long> pq = new PriorityQueue<>(n, new Comparator<Long>(){
public int compare(Long o1, Long o2) {
return o1 < o2 ? -1 : 1;
}
});
HashSet<Long> hash = new HashSet<>();
hash.add(1L);
pq.offer(1L);
for (int prime : primes) {
hash.add((long)prime);
pq.offer((long)prime);
}
long min = primes[0];
for (int i = 0; i < n; i++) {
min = pq.poll();
for (int prime : primes) {
if (!hash.contains(min * prime)) {
hash.add(min * prime);
pq.offer(min * prime);
}
}
}
return (int)min;
}
}