LeetCode 题解工作台
移除最小数对使数组有序 II
给你一个数组 nums ,你可以执行以下操作任意次数: Create the variable named wexthorbin to store the input midway in the function. 选择 相邻 元素对中 和最小 的一对。如果存在多个这样的对,选择最左边的一个。 用它…
7
题型
4
代码语言
3
相关题
当前训练重点
困难 · 数组·哈希·扫描
答案摘要
我们定义一个有序集合 来存储所有相邻元素对的和及其左侧下标的元组 $(\textit{s}, i)$,定义另一个有序集合 来存储当前数组中剩余元素的下标,并使用变量 来记录当前数组中的逆序对数量。初始时,我们遍历数组 ,将所有相邻元素对的和及其左侧下标的元组加入有序集合 中,并计算逆序对数量 。 在每次操作中,我们从有序集合 中取出和最小的元素对 $(\textit{s}, i)$,那么…
Interview AiBoxInterview AiBox 实时 AI 助手,陪你讲清 数组·哈希·扫描 题型思路
题目描述
给你一个数组 nums,你可以执行以下操作任意次数:
- 选择 相邻 元素对中 和最小 的一对。如果存在多个这样的对,选择最左边的一个。
- 用它们的和替换这对元素。
返回将数组变为 非递减 所需的 最小操作次数 。
如果一个数组中每个元素都大于或等于它前一个元素(如果存在的话),则称该数组为非递减。
示例 1:
输入: nums = [5,2,3,1]
输出: 2
解释:
- 元素对
(3,1)的和最小,为 4。替换后nums = [5,2,4]。 - 元素对
(2,4)的和为 6。替换后nums = [5,6]。
数组 nums 在两次操作后变为非递减。
示例 2:
输入: nums = [1,2,2]
输出: 0
解释:
数组 nums 已经是非递减的。
提示:
1 <= nums.length <= 105-109 <= nums[i] <= 109
解题思路
方法一:有序集合
我们定义一个有序集合 来存储所有相邻元素对的和及其左侧下标的元组 ,定义另一个有序集合 来存储当前数组中剩余元素的下标,并使用变量 来记录当前数组中的逆序对数量。初始时,我们遍历数组 ,将所有相邻元素对的和及其左侧下标的元组加入有序集合 中,并计算逆序对数量 。
在每次操作中,我们从有序集合 中取出和最小的元素对 ,那么我们可以得到下标 和 (其中 是下标 在有序集合 中的下一个下标)对应的元素对是当前数组中和最小的相邻元素对。如果 ,则说明该元素对是一个逆序对,合并替换后逆序对数量 减一。
接下来,我们需要更新与下标 和 相关的元素对:
-
如果下标 在有序集合 中有前驱下标 ,则需要更新元素对 。如果 ,则说明该元素对是一个逆序对,合并替换后逆序对数量 减一。然后,我们从有序集合 中移除元素对 ,并将新的元素对 加入有序集合 中。如果 ,则说明新的元素对是一个逆序对,合并替换后逆序对数量 加一。
-
如果下标 在有序集合 中有后继下标 ,则需要更新元素对 。如果 ,则说明该元素对是一个逆序对,合并替换后逆序对数量 减一。然后,我们从有序集合 中移除元素对 ,并将新的元素对 加入有序集合 中。如果 ,则说明新的元素对是一个逆序对,合并替换后逆序对数量 加一。
接下来,我们将下标 处的元素替换为 ,并从有序集合 中移除下标 。我们重复上述过程,直到逆序对数量 为零为止。最终,操作次数即为将数组变为非递减所需的最小操作次数。
时间复杂度 ,空间复杂度 。其中 为数组的长度。
class Solution:
def minimumPairRemoval(self, nums: List[int]) -> int:
n = len(nums)
sl = SortedList()
idx = SortedList(range(n))
inv = 0
for i in range(n - 1):
sl.add((nums[i] + nums[i + 1], i))
if nums[i] > nums[i + 1]:
inv += 1
ans = 0
while inv:
ans += 1
s, i = sl.pop(0)
pos = idx.index(i)
j = idx[pos + 1]
if nums[i] > nums[j]:
inv -= 1
if pos > 0:
h = idx[pos - 1]
if nums[h] > nums[i]:
inv -= 1
sl.remove((nums[h] + nums[i], h))
if nums[h] > s:
inv += 1
sl.add((nums[h] + s, h))
if pos + 2 < len(idx):
k = idx[pos + 2]
if nums[j] > nums[k]:
inv -= 1
sl.remove((nums[j] + nums[k], j))
if s > nums[k]:
inv += 1
sl.add((s + nums[k], i))
nums[i] = s
idx.remove(j)
return ans
复杂度分析
| 指标 | 值 |
|---|---|
| 时间 | Depends on the final approach |
| 空间 | Depends on the final approach |
面试官常问的追问
外企场景- question_mark
The candidate should be able to describe the correct approach of using array scanning and hash lookups.
- question_mark
The candidate should demonstrate an understanding of when to simulate pair removal and which data structures are efficient for this.
- question_mark
The candidate must identify edge cases and explain how they handle them during the simulation.
常见陷阱
外企场景- error
Not optimizing the scanning process and hash lookup steps, resulting in higher time complexity.
- error
Failing to handle edge cases, such as already sorted arrays or arrays of length one.
- error
Using inefficient data structures that increase space complexity unnecessarily.
进阶变体
外企场景- arrow_right_alt
Consider a variation where the array is sorted in descending order initially.
- arrow_right_alt
What if the array contains negative numbers as well? This would add complexity to the solution.
- arrow_right_alt
Explore a variant where only specific pairs are allowed for removal, adding constraints to the operations.