前言
通过丑数了解动态规划的本质思想,举一反三。
一、丑数
1、丑数问题
A.problem
我们把只包含质因子 2、3 和 5 的数称作丑数(Ugly Number)。求按从小到大的顺序的第 n 个丑数。
B.case
示例:
输入: n = 10
输出: 12
解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。
2、动态规划
动态规划本质)动态规划的本质就是找规律,而规律就是动态规划的核心。
丑数CORE核心思想)
所有丑数都是丑数*2|*3|*5的来的,而要乘2|3|5的丑数发源于1即第一个丑数。那么乘出来的最小丑数加入丑数的行列,指针next即去乘较大一点的丑数,然后开始新的竞争,三者next同理。
抓住核心思想就抓住了算法,便于举一反三,摸清联系。
package com.xhu.offer;
public class UglyNumber {
/**
* @param n
* @return
* @function 求第n个丑数
* CORE核心思想,所有丑数都是丑数*2|*3|*5的来的,而要乘2|3|5的丑数发源于1即第一个丑数.
* 为了取到第n个丑数,就不得不取上面三个乘出来的最小丑数加入丑数队列。
* 每次取到最小丑数时,就需要去乘大一点的丑数来竞争最小丑数。
*/
public int nthUglyNumber(int n) {
if (n == 0) return -1;
int n2, n3, n5;
n2 = n3 = n5 = 0;
int[] dp = new int[n];
dp[0] = 1;
//一个指针指向第一个丑数,复制3份,根据是否竞争成功来移动自己的指针。
for (int i = 1; i < n; i++) {
int a = dp[n2] * 2, b = dp[n3] * 3, c = dp[n5] * 5;
//判断最小值
dp[i] = a < b ? a < c ? a : c : b < c ? b : c;
//判断谁乘出来的是最小丑数,则index++。这里有相等的情况,其index需同时加加来进行新一轮的竞争。
n2 += a == dp[i] ? 1 : 0;
n3 += b == dp[i] ? 1 : 0;
n5 += c == dp[i] ? 1 : 0;
}
return dp[n - 1];
}
}
总结
1)动态规划即规律。
2)问题解决在于问题的核心。
参考文献
[1] Leetcode 原题