难度: Hard
Submission
运行时间: 130 ms
内存: 35.3 MB
# https://leetcode.cn/u/l00/ class Solution: def numsGame(self, nums: List[int]) -> List[int]: MOD = 1_000_000_007 ans = [0] nums = [i - num for i, num in enumerate(nums)] lower = higher = nums[0] for i, num in enumerate(nums[1:], 1): if lower > num: lower = num if higher < num: higher = num # 标准值左右两边的点位数量差值 totalDiff = 0 # 标准值,也就是当前最佳数值,得出最佳的结果的标准 cur = nums[0] - lower cnt = [0] * (higher - lower + 1) cnt[cur] = 1 # 一开始标准值必然就是第一个数,然后枚举后面全部情况 res = 0 for num in nums[1:]: diff = num - lower cnt[diff] += 1 # 新值与标准值一致,不需要改变 if diff == cur: ans.append(res) continue # 判断新值与标准值的大小,对比其添加方向上的数量是否超过另一个方向的数量 # 如果超过,就进行移动,这样必然形成更优的结果 if diff > cur: totalDiff -= 1 res += diff - cur if totalDiff < -cnt[cur]: target = cur + 1 while cnt[target] == 0: target += 1 totalDiff += cnt[cur] res += (target - cur) * (totalDiff) totalDiff += cnt[target] cur = target else: totalDiff += 1 res += cur - diff if totalDiff > cnt[cur]: target = cur - 1 while cnt[target] == 0: target -= 1 totalDiff -= cnt[cur] res += (target - cur) * (totalDiff) totalDiff -= cnt[target] cur = target res %= MOD ans.append(res) return ans
Explain
本题目的是通过最少的操作次数,使得数组nums的前i个元素满足nums[a]+1 == nums[a+1]的条件。为了方便处理,我们首先将数组nums中的每个元素减去其索引,得到一个新的数组。接着,我们从左到右遍历这个新数组,并维护一个当前的标准值cur,以及左右两边的元素数量差值totalDiff。每次遍历到一个新元素时,我们更新左右两边的元素数量,并根据这个数量差值来调整标准值cur,以及计算出当前的最少操作次数res,并将其加入到答案数组ans中。
时间复杂度: O(n)
空间复杂度: O(n)
# https://leetcode.cn/u/l00/ class Solution: def numsGame(self, nums: List[int]) -> List[int]: MOD = 1_000_000_007 ans = [0] nums = [i - num for i, num in enumerate(nums)] lower = higher = nums[0] for i, num in enumerate(nums[1:], 1): if lower > num: lower = num if higher < num: higher = num # 标准值左右两边的点位数量差值 totalDiff = 0 # 标准值,也就是当前最佳数值,得出最佳的结果的标准 cur = nums[0] - lower cnt = [0] * (higher - lower + 1) cnt[cur] = 1 # 一开始标准值必然就是第一个数,然后枚举后面全部情况 res = 0 for num in nums[1:]: diff = num - lower cnt[diff] += 1 # 新值与标准值一致,不需要改变 if diff == cur: ans.append(res) continue # 判断新值与标准值的大小,对比其添加方向上的数量是否超过另一个方向的数量 # 如果超过,就进行移动,这样必然形成更优的结果 if diff > cur: totalDiff -= 1 res += diff - cur if totalDiff < -cnt[cur]: target = cur + 1 while cnt[target] == 0: target += 1 totalDiff += cnt[cur] res += (target - cur) * (totalDiff) totalDiff += cnt[target] cur = target else: totalDiff += 1 res += cur - diff if totalDiff > cnt[cur]: target = cur - 1 while cnt[target] == 0: target -= 1 totalDiff -= cnt[cur] res += (target - cur) * (totalDiff) totalDiff -= cnt[target] cur = target res %= MOD ans.append(res) return ans
Explore
在处理数组时,对每个元素减去其索引的操作是为了将问题转化为寻找一个连续的、以0开始递增的数列。原问题要求nums[a]+1 == nums[a+1],减去索引后,这个条件变为新数组中的相邻元素应该相等。这种转换简化了问题,使得我们可以通过维护一个当前的标准值和左右两边的元素数量差值来优化操作,从而更有效地达到目标条件。
在算法中,`cur`表示当前的最优或标准值,即使得操作次数最小的目标数值。`totalDiff`是左右两边相对于`cur`的元素数量差值,用于判断是否需要调整`cur`以达到更优的操作次数。当新的元素数值与`cur`不一致时,根据它们的差值和`totalDiff`的正负,我们可以确定是增加还是减少`cur`,并计算因此产生的操作次数。调整`cur`时,我们还需要考虑跳过那些计数为0的值,以确保`cur`总是指向存在的元素,从而最小化操作次数。
当需要调整标准值`cur`到新的目标`target`,且`target`处的元素计数为0时,算法通过循环遍历`cnt`数组来寻找下一个非零计数的位置。这个遍历过程涉及向左或向右检查直到找到有元素的位置。通过这种方式,我们确保了`cur`总是更新到有效的、有实际元素存在的位置,即使需要跳过一些计数为0的间隔。这个过程是通过简单的循环实现的,保证了在调整`cur`时总能找到最近的有效目标值。