一、题目描述
给你一个下标从 0 开始的整数数组 nums
和一个 非负 整数 k
。
在一步操作中,你可以执行下述指令:
- 在范围
[0, nums.length - 1]
中选择一个 此前没有选过 的下标i
。 - 将
nums[i]
替换为范围[nums[i] - k, nums[i] + k]
内的任一整数。
数组的 美丽值 定义为数组中由相等元素组成的最长子序列的长度。
对数组 nums
执行上述操作任意次后,返回数组可能取得的 最大 美丽值。
注意:你 只 能对每个下标执行 一次 此操作。
数组的 子序列 定义是:经由原数组删除一些元素(也可能不删除)得到的一个新数组,且在此过程中剩余元素的顺序不发生改变。
示例 1:
输入:nums = [4,6,1,2], k = 2 输出:3 解释:在这个示例中,我们执行下述操作: - 选择下标 1 ,将其替换为 4(从范围 [4,8] 中选出),此时 nums = [4,4,1,2] 。 - 选择下标 3 ,将其替换为 4(从范围 [0,4] 中选出),此时 nums = [4,4,1,4] 。 执行上述操作后,数组的美丽值是 3(子序列由下标 0 、1 、3 对应的元素组成)。 可以证明 3 是我们可以得到的由相等元素组成的最长子序列长度。
二、思路分析
这个题目的意思就是,给你一个数k,有n个[num[i]-k,num[i]+k]区间。找出这些区间的交集,也就是这些区间覆盖最多的那个数。
看似还需要找到替换成哪个数,其实本质就是寻找区间重叠最多的那个数,替换为这个就行。
首先我们对每个区间进行排序,然后遍历每个区间,看当前区间的右端点可以覆盖几个区间,也就是比几个区间的左端点大。我们只需要求得覆盖几个区间的数量,而不用保存那个数,因为求的是最长子序列的长度。
因为这个题的区间长度是一样的,在草稿上画一下就知道了,其实不需要考虑区间,我们只需要当前num[i]+2*k比几个num[i]大即可,也就是能覆盖到几个区间。
又因为这个数组是我们排序好,我们使用二分查找来找到num[i]+2*k的插入位置,就能知道他比几个num[i]大了。
具体实现很简单,请看下面的代码:
三、代码实现
class Solution:def maximumBeauty(self, nums: List[int], k: int) -> int:nums.sort()num = 0for i in range(len(nums)):# 找到nums[i]+2*k可以插入的位置left = bisect.bisect_right(nums, nums[i]+2*k)# 计算出这个位置相对于i的长度,也就是可以覆盖区间的数量num = max(num,left - i)return num
如果对于求解长度不定的,最大重叠次数。我们可以使用差分数组来计算每个数被覆盖多少次。代码如下:
class Solution:def maximumCoveredNumber(self, intervals: List[List[int]]) -> int:# 找到区间的最大值max_value = max([end for _, end in intervals])# 初始化差分数组diff = [0] * (max_value + 2) # 为了避免越界,我们多开一个空间# 对每个区间进行差分更新for start, end in intervals:diff[start] += 1diff[end + 1] -= 1 # 注意,end + 1 位置的差值需要减去# 计算前缀和,找出最大覆盖次数current_cover = 0max_cover = 0for i in range(max_value + 1):current_cover += diff[i]max_cover = max(max_cover, current_cover)return max_cover