第 n 个丑数

自己想了两天都没思路啊啊啊啊啊我真是太笨了。看了他的 tag,说是用到了动态规划,于是特意看了算法导论里动态规划的部分。然而只是说了其思想,第一步构建合理的数据结构,第二部以递归的形式求解。可见水无常形,动态规划并不是单纯的公式就可以解决的。那么具体如何处理呢?

第一是,什么时候会用到动态规划,就是这样一种情况:后面的结果来自于前面的结果,而前面的结果又已经被求解后存储。前者意味着它的递归结构,后者有种空间换时间的意味。

明确这个就进入第二个问题,丑数是什么?

除了 1 之外,由且只由 2 3 5 三种素因子构成的数即为丑数。既然素因子只能有 2 3 5,那么后面的丑数必然是通过前面的丑数乘以 2/3/5 得到的。

后面的数由前面的求出,而前面的丑数被求出后又储存在数组中,这两点正是之前提到的递归和空间换时间。

那么新的丑数可能是怎么构成的呢?三种:2 *a/ 3 * b/ 5 * c 因此设置三个标记,分别指示其中 a, b, c 的位置。

其中,最小的数字成为新的丑数。而在其被选为新丑数之后,下一个新丑数必然要比这个数大(废话) 所以要将相应的标记后移,以确保下一个新丑数的三个选择均大于当前最大的丑数。

有了以上说明之后,就可以很好理解一下算法了:

int nthUglyNumber(int n) {
    if (n < 1){
        return 0;
    }
    
    vector<int> ugliness{1};
    
    auto index2 = 0;
    auto index3 = 0;
    auto index5 = 0;

    auto saveNewUglyIncreaseIt = [&]
    {
        auto const val2    = ugliness[index2] * 2;
        auto const val3    = ugliness[index3] * 3;
        auto const val5    = ugliness[index5] * 5;
        auto const newUgly = min(val2, min(val3, val5));
        
        if (newUgly == val2){
            ++index2;
        }
        if (newUgly == val3){
            ++index3;
        }
        if (newUgly == val5){
            ++index5;
        }
        ugliness.push_back(newUgly);
    };
    
    for (int i = 1; i != n; ++i){
        saveNewUglyIncreaseIt();
    }
    return ugliness.back();
}
原文地址:https://www.cnblogs.com/wuOverflow/p/4768162.html