给你一个整数数组 nums ,一个整数 k 和一个整数 multiplier 。
你需要对 nums 执行 k 次操作,每次操作中:
找到 nums 中的 最小 值 x ,如果存在多个最小值,选择最 前面 的一个。
将 x 替换为 x * multiplier 。
请你返回执行完 k 次乘运算之后,最终的 nums 数组。
示例 1:
输入:nums = 2,1,3,5,6, k = 5, multiplier = 2
输出:8,4,6,5,6
解释:
操作 结果
1 次操作后 2, 2, 3, 5, 6
2 次操作后 4, 2, 3, 5, 6
3 次操作后 4, 4, 3, 5, 6
4 次操作后 4, 4, 6, 5, 6
5 次操作后 8, 4, 6, 5, 6
示例 2:
输入:nums = 1,2, k = 3, multiplier = 4
输出:16,8
解释:
操作 结果
1 次操作后 4, 2
2 次操作后 4, 8
3 次操作后 16, 8
提示:
1 <= nums.length <= 100
1 <= numsi <= 100
1 <= k <= 10
1 <= multiplier <= 5
对于两个数字x和y,假设x<y,且x * multiplier > y,那么两个进行乘算的顺序是一直重复的x、y、x、y、x...,因为x * multiplier > y后,下一步就是x * multiplier < y * multiplier。对于多个数字,也是同样的重复,我们可以先进行一轮乘算,直到原数组中的最大值变为最小值,然后再乘算一次,之后就都是重复操作了,如果此时还剩下k次操作,那么剩下每个元素至少会执行k/nums.size()次乘算,而且前k%nums.size()个元素还会进行更多的一次乘算,这可以用快速幂来计算:
cpp
class Solution {
public:
vector<int> getFinalState(vector<int>& nums, int k, int multiplier) {
// O(n)空间
vector<pair<int, int>> h;
// O(n)时间
for (int i = 0; i < nums.size(); ++i) {
h.push_back({nums[i], i});
}
// 堆化,O(n)时间
make_heap(h.begin(), h.end(), greater<>());
// 先进行一轮乘算
int mx = ranges::max(nums);
// 如果数组中最大值为U,m为multiplier,对于该最大值需要循环以m为底U的对数次
// 数组中最差有O(n)个最大值
while (h[0].first <= mx && k > 0) {
// O(logn)时间
pop_heap(h.begin(), h.end(), greater<>());
h.back().first *= multiplier;
push_heap(h.begin(), h.end(), greater<>());
--k;
}
sort(h.begin(), h.end());
for (int i = 0; i < nums.size(); ++i) {
auto &[v, j] = h[i];
int repeatNum = k / nums.size();
if (i < (k % nums.size())) {
++repeatNum;
}
nums[j] = v * pow(multiplier, repeatNum);
}
return nums;
}
int pow(long long num, int n) {
int ans = 1;
while (n) {
if (n & 1) {
ans *= num;
}
num *= num;
n >>= 1;
}
return ans;
}
};
如果nums的大小为n,数组中最大值为U,multiplier为m,则此算法时间复杂度为O(nlognlogm_{m}mU),空间复杂度为O(n)。