Every day a Leetcode
题目来源:2968. 执行操作使频率分数最大
解法1:贪心 + 前缀和 + 滑动窗口
基于贪心的思想,将数组 nums 的所有元素变为 nums 的中位数是最优的。
把数组排序后,要变成一样的数必然在一个连续子数组中,那么用滑动窗口来做,枚举子数组的右端点 right,然后维护子数组的左端点 left。
根据中位数贪心,最优做法是把子数组内的元素都变成子数组的中位数,操作次数如果超过 k,就必须移动左端点。
求出数组的前缀和,就可以在 O(1) 的时间复杂度下算出操作次数了。
代码:
/*
* @lc app=leetcode.cn id=2968 lang=cpp
*
* [2968] 执行操作使频率分数最大
*/
// @lc code=start
// 贪心 + 前缀和 + 滑动窗口
class Solution
{
public:
int maxFrequencyScore(vector<int> &nums, long long k)
{
// 特判
if (nums.empty())
return 0;
int n = nums.size();
sort(nums.begin(), nums.end());
vector<long long> preSum(n + 1, 0);
for (int i = 1; i <= n; i++)
preSum[i] = preSum[i - 1] + nums[i - 1];
auto calDistance = [&](int left, int i, int right) -> long long
{
long long left_distance = (long long)nums[i] * (i - left) - (preSum[i] - preSum[left]);
long long right_distance = (preSum[right + 1] - preSum[i + 1]) - (long long)nums[i] * (right - i);
return left_distance + right_distance;
};
int ans = 0;
int left = 0;
for (int right = 0; right < n; right++)
{
while (calDistance(left, (left + right) / 2, right) > k)
left++;
ans = max(ans, right - left + 1);
}
return ans;
}
};
// @lc code=end
结果:
复杂度分析:
时间复杂度:O(nlogn),其中 n 是数组 nums 的长度。
空间复杂度:O(n),其中 n 是数组 nums 的长度。