Medium
题目描述
给定一个长度为 n 的数组 nums。同时给定一个整数 k。
你需要对 nums 执行一次以下操作:
- 选择一个子数组
nums[i..j],其中0 <= i <= j <= n - 1。 - 选择一个整数
x,将x加到nums[i..j]中的所有元素上。
找出操作后值 k 的最大频率。
示例 1:
输入:nums = [1,2,3,4,5,6], k = 1
输出:2
解释:将 -5 加到 nums[2..5] 后,1 在 [1, 2, -2, -1, 0, 1] 中的频率为 2。
示例 2:
输入:nums = [10,2,3,4,5,5,4,3,2,2], k = 10
输出:4
解释:将 8 加到 nums[1..9] 后,10 在 [10, 10, 11, 12, 13, 13, 12, 11, 10, 10] 中的频率为 4。
约束条件:
1 <= n == nums.length <= 10^51 <= nums[i] <= 501 <= k <= 50
提示:
- 固定要转换为
k的元素。 - 使用前缀和来优化计算元素出现次数。
解题思路
这道题的核心思路是枚举所有可能被转换为 k 的值,然后对每个值计算最大可能的频率。
主要思路:
枚举转换值:由于数组元素范围是 1-50,我们可以枚举所有可能的原始值
v,计算将值为v的元素转换为k的情况。转换条件:要将值为
v的元素转换为k,需要在包含这些元素的子数组上加上k - v。最大子数组问题:对于每个固定的
v,问题转化为找到一个子数组,使得其中值为v的元素个数最多。这可以用类似最大子数组和的动态规划方法解决。动态规划:
- 将数组转换为 0/1 数组,值为
v的位置标记为 1,其他为 0 - 使用 Kadane 算法找到最大子数组和,即包含最多
v的子数组 - 最终答案是原本就是
k的元素个数 + 转换得到的最多k的个数
- 将数组转换为 0/1 数组,值为
优化:可以不用真正构建 0/1 数组,直接在遍历过程中计算。
时间复杂度为 O(50n),由于常数较小,在给定约束下是可行的。
代码实现
class Solution {
public:
int maxFrequency(vector<int>& nums, int k) {
int n = nums.size();
int maxFreq = 0;
// 统计原本就是k的元素个数
int originalK = 0;
for (int num : nums) {
if (num == k) originalK++;
}
// 枚举所有可能的原始值
for (int v = 1; v <= 50; v++) {
if (v == k) continue; // 跳过k本身
// 使用Kadane算法找最大子数组
int maxSum = 0, currentSum = 0;
for (int num : nums) {
if (num == v) {
currentSum += 1;
} else {
currentSum = max(0, currentSum);
}
maxSum = max(maxSum, currentSum);
}
maxFreq = max(maxFreq, originalK + maxSum);
}
// 考虑不进行任何转换的情况
maxFreq = max(maxFreq, originalK);
return maxFreq;
}
};
class Solution:
def maxFrequency(self, nums: List[int], k: int) -> int:
n = len(nums)
max_freq = 0
# 统计原本就是k的元素个数
original_k = nums.count(k)
# 枚举所有可能的原始值
for v in range(1, 51):
if v == k:
continue
# 使用Kadane算法找最大子数组
max_sum = 0
current_sum = 0
for num in nums:
if num == v:
current_sum += 1
else:
current_sum = max(0, current_sum)
max_sum = max(max_sum, current_sum)
max_freq = max(max_freq, original_k + max_sum)
# 考虑不进行任何转换的情况
max_freq = max(max_freq, original_k)
return max_freq
public class Solution {
public int MaxFrequency(int[] nums, int k) {
int n = nums.Length;
int maxFreq = 0;
// 统计原本就是k的元素个数
int originalK = 0;
foreach (int num in nums) {
if (num == k) originalK++;
}
// 枚举所有可能的原始值
for (int v = 1; v <= 50; v++) {
if (v == k) continue;
// 使用Kadane算法找最大子数组
int maxSum = 0, currentSum = 0;
foreach (int num in nums) {
if (num == v) {
currentSum += 1;
} else {
currentSum = Math.Max(0, currentSum);
}
maxSum = Math.Max(maxSum, currentSum);
}
maxFreq = Math.Max(maxFreq, originalK + maxSum);
}
// 考虑不进行任何转换的情况
maxFreq = Math.Max(maxFreq, originalK);
return maxFreq;
}
}
var maxFrequency = function(nums, k) {
const n = nums.length;
let maxFreq = 0;
// Count initial frequency of k
let initialCount = 0;
for (let num of nums) {
if (num === k) initialCount++;
}
// Try all possible subarrays
for (let i = 0; i < n; i++) {
for (let j = i; j < n; j++) {
// For subarray [i, j], we need to add (k - nums[x]) to make nums[x] = k
let freq = initialCount;
// Remove original k's in the subarray range
for (let x = i; x <= j; x++) {
if (nums[x] === k) freq--;
}
// Add the length of subarray (all will become k)
freq += (j - i + 1);
maxFreq = Math.max(maxFreq, freq);
}
}
return maxFreq;
};
复杂度分析
| 复杂度类型 | 分析 |
|---|---|
| 时间复杂度 | O(50 × n) = O(n),其中 n 是数组长度。需要枚举50个可能的值,每个值需要O(n)时间用Kadane算法计算 |
| 空间复杂度 | O(1),只使用了常数个额外变量 |