题目套了一个素数的大主题,但其实和素数算法没什么关系,简而言之,就是提供一个数组arr,计算仅由arr数组中不同元素乘积出的数字,从小到大排序的第n个数字。
大致思路是dp数组中每个数字都可以由之前dp数组中的数字乘以prime数组中的各个数字得到,问题是,哪个dp数字乘以哪个prime数字可以得到下一个dp呢?无非是dp[0] * prime 与dp[1] * prime与dp[2]*prime中取第n个最小数。
那么我们可以用一个辅助数组point记录每个prime乘以第几个dp可能得到当前最小值,然后更新point数组,与最小值相等的point * prime的那个位置 + 1,这样每个prime数字乘的就是下一个最小的dp数字。
以【2,7,11,13】为例
- dp[0] = min(2, 3, 5, 7) ->2
- dp[1] = min(2 * 2, 3, 5, 7) ->3
- dp[2] = min(2 * 2, 2 * 3, 5, 7) ->4
- dp[3] = min(3 * 2 , 2 * 3, 5, 7) ->5
- dp[4] = min(3 * 2, 2 * 3, 2 * 5, 7) -> 6
- dp[5] = min(4 * 2, 3 * 3, 2 * 5, 7) ->7
- …
翻译
- dp[0] = min(dp[0] * 2, dp[0] * 3, dp[0] * 5, dp[0] * 7) ->2
- dp[1] = min(dp[1] * 2, dp[0] * 3, dp[0] * 5, dp[0] * 7) ->3
- dp[2] = min(dp[1] * 2, dp[1] * 3, dp[0] * 5, dp[0] * 7) ->4
- dp[3] = min(dp[2] * 2, dp[1] * 3, dp[0] * 5, dp[0] * 7) ->5
- dp[4] = min(dp[2] * 2, dp[1] * 3, dp[1] * 5, dp[0] * 7) -> 6
- dp[5] = min(dp[2] * 2, dp[1] * 3, dp[1] * 5, dp[1] * 7) ->7
- …
注意!如第5步,2 * 3与3 * 2都是最小值,发生这种情况是因为dp数组记录了prime数组本身,就会发生交叉乘的情况,这时要一起改变相应的辅助数组值。
class Solution {
public:
int nthSuperUglyNumber(int n, vector<int>& primes) {
int primesSize = primes.size();
vector<int> dp(n + 1, 1);
vector<int> point(primesSize, 0);//每个质数对应的倍数(dp位置)
for (int i = 1; i < n; i++){//dp从第二个开始计算
int min_p = INT_MAX;
for (int j = 0; j < primesSize; j++){
min_p = min(min_p, dp[point[j]] *primes[j]);
}
dp[i] = min_p;
for(int j = 0; j < primesSize; j++)
{
if(dp[i] == dp[point[j]] * primes[j])//dp1=dp0*...
{
point[j]++;
}
}
cout << dp[i] << endl;
}
return dp[n - 1];
}
};