LeetCode-2009. 使数组连续的最少操作数【数组 哈希表 二分查找 滑动窗口】
- 题目描述:
- 解题思路一:正难则反+滑动窗口
- 解题思路二:0
- 解题思路三:0
题目描述:
给你一个整数数组 nums 。每一次操作中,你可以将 nums 中 任意 一个元素替换成 任意 整数。
如果 nums 满足以下条件,那么它是 连续的 :
nums 中所有元素都是 互不相同 的。
nums 中 最大 元素与 最小 元素的差等于 nums.length - 1 。
比方说,nums = [4, 2, 5, 3] 是 连续的 ,但是 nums = [1, 2, 3, 5, 6] 不是连续的 。
请你返回使 nums 连续 的 最少 操作次数。
示例 1:
输入:nums = [4,2,5,3]
输出:0
解释:nums 已经是连续的了。
示例 2:
输入:nums = [1,2,3,5,6]
输出:1
解释:一个可能的解是将最后一个元素变为 4 。
结果数组为 [1,2,3,5,4] ,是连续数组。
示例 3:
输入:nums = [1,10,100,1000]
输出:3
解释:一个可能的解是:
- 将第二个元素变为 2 。
- 将第三个元素变为 3 。
- 将第四个元素变为 4 。
结果数组为 [1,2,3,4] ,是连续数组。
提示:
1 <= nums.length <= 105
1 <= nums[i] <= 109
解题思路一:正难则反+滑动窗口
正难则反,考虑最多保留多少个元素不变。
由于元素的位置不影响答案,且要求所有元素互不相同,我们可以将 nums 从小到大排序,并去掉重复元素。
设 x 是连续数字的最大值,则连续数字的范围为闭区间 [x−n+1,x],其中 n 是 nums 的长度。
设 a 为 nums 排序去重后的数组。把 a[i]画在一条数轴上,本题相当于有一个长度为 n 的滑动窗口,我们需要计算窗口内最多可以包含多少个数轴上的点。
定理:只需要枚举 a[i] 作为窗口的右端点。
证明:在窗口从左向右滑动的过程中,如果窗口右端点处没有点,那么继续滑动,在滑到下一个点之前,窗口内包含的点的个数是不会增多的。
为了算出窗口内有多少个点,我们需要知道窗口包含的最左边的点在哪,设这个点的位置是 a[left],则它必须大于等于窗口的左边界,即
a[left]≥a[i]−n+1
此时窗口内有 i−left+1个点。
注意i - left + 1是nums数组中在滑动窗口中的个数
class Solution:
def minOperations(self, nums: List[int]) -> int:
n = len(nums)
a = sorted(set(nums)) # 去重排序
ans = left = 0
for i, x in enumerate(a):
while a[left] < x - n + 1: # a[left] 不在窗口内
left += 1
ans = max(ans, i - left + 1) # 统计最长的连续数组长度
return n - ans
时间复杂度:O(nlogn)
空间复杂度:O(n) 哈希表
解题思路二:0
时间复杂度:O(n)
空间复杂度:O(n)
解题思路三:0
时间复杂度:O(n)
空间复杂度:O(n)