⚖️ 删除数对后的最小数组长度
📝 题目描述
给你一个下标从0开始的非递减整数数组nums
。
你可以执行以下操作任意次:
- 选择两个下标
i
和j
,满足nums[i] < nums[j]
。 - 将
nums
中下标在i
和j
处的元素删除。剩余元素按照原来的顺序组成新的数组,下标也重新从0开始编号。
请你返回一个整数,表示执行以上操作任意次后(可以执行0次),nums
数组的最小数组长度。
📋 代码模板
java
class Solution {
public int minLengthAfterRemovals(List<Integer> nums) {
}
}
typescript
function minLengthAfterRemovals(nums: number[]): number {
}
💡 提示
是非递减 数组
🚀 示例
🖊️ 题解
这道题的核心思想是反复对数组中的两个不同数进行相互抵消操作,找出能够剩下的最少数量。
假设
- 如果
,其余所有 个非 数都可以与 消除,因此最后剩下 个数。 - 如果
,且 是偶数,那么其余数相互消除肯定能剩下 个数,然后再与 消除,最后剩下 个数。 - 如果
,且 是奇数,同上,最后可以剩下 个数。
综上所述,解决本题的关键是求出
答案是有的。由于
因此我们可以假设
如果
,那么剩下的数的个数肯定大于 。而在这种情况下 的值最大为 。 如果
,那么剩下的数的个数为 或者 。而在这种情况下 的值肯定 。
可以看到,我们只需要取
java
class Solution {
public int minLengthAfterRemovals(List<Integer> nums) {
int n = nums.size();
int x = nums.get(n / 2);
int maxCnt = binarySearch(nums, x + 1) - binarySearch(nums, x);
return Math.max(2 * maxCnt - n, n % 2);
}
private int binarySearch(List<Integer> nums, int target) {
int low = 0, high = nums.size() - 1;
while (low <= high) {
int mid = low + ((high - low) >> 1);
if (nums.get(mid) >= target) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return low;
}
}
typescript
function minLengthAfterRemovals(nums: number[]): number {
const n = nums.length;
const binarySearch = (target: number): number => {
let low = 0, high = n - 1;
while (low <= high) {
const mid = low + Math.floor((high - low) / 2);
if (nums[mid] >= target) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return low;
}
const x = nums[Math.floor(n / 2)];
const maxCnt = binarySearch(x + 1) - binarySearch(x);
return Math.max(2 * maxCnt - n, n % 2);
}
💭 复杂度分析
基于二分查找
的解决方案的复杂度分析如下。
- 时间复杂度:
。其中 为 。 - 空间复杂度:
。