记力扣.2779 数组的最大美丽值 练习理解
给你一个下标从 0 开始的整数数组
nums
和一个 非负 整数k
。在一步操作中,你可以执行下述指令:
- 在范围
[0, nums.length - 1]
中选择一个 此前没有选过 的下标i
。- 将
nums[i]
替换为范围[nums[i] - k, nums[i] + k]
内的任一整数。数组的 美丽值 定义为数组中由相等元素组成的最长子序列的长度。
对数组
nums
执行上述操作任意次后,返回数组可能取得的 最大 美丽值。注意:你 只 能对每个下标执行 一次 此操作。
数组的 子序列 定义是:经由原数组删除一些元素(也可能不删除)得到的一个新数组,且在此过程中剩余元素的顺序不发生改变。
思路:
例如:4126,k=2,题目意思一个数字最多改一次,改的条件是最多相同的数字的长度,我们换个思路可以把每个数字看成一个【n-k,n+k】的区间,从小到大排列,看最多有多少个数字区间能有交集,如果有交集即为存在相同的数可以相等
from typing import List
from collections import defaultdict
class Solution:def maximumBeauty(self,nums:List[int],k:int)->int:left=max_len=0nums.sort()for i in range(len(nums)):if nums[i]-nums[left] >2*k:left +=1max_len=max(max_len,i-left+1)return max_len
例:子序列按原顺序选
[4,1,6]
- 分析每个元素可覆盖的范围:4±2 → [2,6];1±2 → [-1,3];6±2 → [4,8]。
- 找 “能覆盖最多元素的公共值”:比如值 3:覆盖 4(3 在 [2,6])、1(3 在 [-1,3]),但不覆盖 6(3 不在 [4,8])→ 2 个元素;比如值 5:覆盖 4(5 在 [2,6])、6(5 在 [4,8]),但不覆盖 1(5 不在 [-1,3])→ 2 个元素;结论:这 3 个元素最多 2 个能统一,最长子序列长度为 2。
难点:
1. 从 "子序列" 到 "连续子数组" 的转化思维
问题定义中美丽值是基于 "子序列" 的,但解法却用了 "连续子数组"(滑动窗口)来求解,这是第一个难点。
关键在于理解:当数组排序后,能通过操作变成相同值的元素必然是连续的一段。因为排序后数值是递增的,如果两个不相邻的元素能变成相同值,那么它们之间的所有元素也一定能变成这个值。
这一转化将问题从寻找任意子序列简化为寻找连续子数组,大大降低了难度。
2. "2k" 区间的意义理解
为什么判断条件是
nums[i] - nums[left] > 2 * k
而不是k
?这是因为每个元素都可以上下浮动 k,所以两个元素能够调整到同一个值的最大允许差距是 2k:
- 较小的元素可以增加最多 k
- 较大的元素可以减少最多 k
- 两者最大可重叠的区间需要满足:大元素 - 小元素 ≤ 2k
理解这一区间特性是正确设置滑动窗口收缩条件的关键。
3. 排序的作用与必要性
为什么一定要先排序?这是因为:
- 未排序时,符合条件的元素可能分散在数组各处,无法用滑动窗口高效寻找
- 排序后,数值相近的元素集中在一起,使得滑动窗口能够有效工作
- 排序不影响最终结果,因为美丽值只关心元素数量而不关心它们的原始顺序