| title | 462. 最小操作次数使数组元素相等 II | ||||||||
|---|---|---|---|---|---|---|---|---|---|
| description | LeetCode 462. 最小操作次数使数组元素相等 II题解,Minimum Moves to Equal Array Elements II,包含解题思路、复杂度分析以及完整的 JavaScript 代码实现。 | ||||||||
| keywords |
|
🟠 Medium 🔖 数组 数学 排序 🔗 力扣 LeetCode
Given an integer array nums of size n, return the minimum number of moves
required to make all array elements equal.
In one move, you can increment or decrement an element of the array by 1.
Test cases are designed so that the answer will fit in a 32-bit integer.
Example 1:
Input: nums = [1,2,3]
Output: 2
Explanation:
Only two moves are needed (remember each move increments or decrements one element):
[1 ,2,3] => [2,2,3] => [2,2,2]
Example 2:
Input: nums = [1,10,2,9]
Output: 16
Constraints:
n == nums.length1 <= nums.length <= 10^5-10^9 <= nums[i] <= 10^9
给你一个长度为 n 的整数数组 nums ,返回使所有数组元素相等需要的最小操作数。
在一次操作中,你可以使数组中的一个元素加 1 或者减 1 。
测试用例经过设计以使答案在 32 位 整数范围内。
示例 1:
输入: nums = [1,2,3]
输出: 2
解释:
只需要两次操作(每次操作指南使一个元素加 1 或减 1):
[1 ,2,3] => [2,2,3] => [2,2,2]
示例 2:
输入: nums = [1,10,2,9]
输出: 16
提示:
n == nums.length1 <= nums.length <= 10^5-10^9 <= nums[i] <= 10^9
- 排序
nums,确定中位数mid = nums[n/2]。 - 遍历
nums,计算所有元素变成mid需要的步数。
- 时间复杂度:
O(n log n),排序O(n log n),求和O(n)。 - 空间复杂度:
O(1),只使用了常数级变量。
我们只需要找到中位数,不需要完全排序。因此,可以使用快速选择算法(QuickSelect)在 O(n) 时间内找到中位数。
- 采用**分区(partition)**的方式,每次将一个元素放到正确的位置。
- 但 只递归处理一侧(与快速排序不同)。
- 时间复杂度:
O(n),排序O(n),求和O(n)。 - 空间复杂度:
O(1),只使用了常数级变量。
::: code-tabs @tab 排序
/**
* @param {number[]} nums
* @return {number}
*/
var minMoves2 = function (nums) {
nums.sort((a, b) => a - b);
const mid = nums[(nums.length / 2) | 0]; // 选取中位数
return nums.reduce((acc, cur) => acc + Math.abs(cur - mid), 0);
};@tab 快速选择排序
/**
* @param {number[]} nums
* @return {number}
*/
var minMoves2 = function (nums) {
const n = nums.length;
// 快速选择算法: 找到第 k 小的元素(k = n // 2)
function quickSelect(left, right, k) {
if (left >= right) return nums[left];
let pivot = partition(left, right);
if (pivot === k) return nums[pivot];
return pivot < k
? quickSelect(pivot + 1, right, k)
: quickSelect(left, pivot - 1, k);
}
// Lomuto partition
function partition(left, right) {
let pivot = nums[right],
i = left;
for (let j = left; j < right; j++) {
if (nums[j] < pivot) {
[nums[i], nums[j]] = [nums[j], nums[i]];
i++;
}
}
[nums[i], nums[right]] = [nums[right], nums[i]];
return i;
}
// 找到中位数
const mid = quickSelect(0, n - 1, Math.floor(n / 2));
// 计算总步数
return nums.reduce((acc, num) => acc + Math.abs(num - mid), 0);
};:::
| 题号 | 标题 | 题解 | 标签 | 难度 | 力扣 |
|---|---|---|---|---|---|
| 296 | 最佳的碰头地点 🔒 | 数组 数学 矩阵 1+ |
🔴 | 🀄️ 🔗 | |
| 453 | 最小操作次数使数组元素相等 | [✓] | 数组 数学 |
🟠 | 🀄️ 🔗 |
| 2033 | 获取单值网格的最小操作数 | [✓] | 数组 数学 矩阵 1+ |
🟠 | 🀄️ 🔗 |
| 2171 | 拿出最少数目的魔法豆 | 贪心 数组 枚举 2+ |
🟠 | 🀄️ 🔗 | |
| 2448 | 使数组相等的最小开销 | 贪心 数组 二分查找 2+ |
🔴 | 🀄️ 🔗 | |
| 2602 | 使数组元素全部相等的最少操作次数 | 数组 二分查找 前缀和 1+ |
🟠 | 🀄️ 🔗 | |
| 2967 | 使数组成为等数数组的最小代价 | 贪心 数组 数学 2+ |
🟠 | 🀄️ 🔗 |