求出最多标记下标

题目

6367. 求出最多标记下标


给你一个下标从 0 开始的整数数组 nums 。

一开始,所有下标都没有被标记。你可以执行以下操作任意次:

  • 选择两个 互不相同且未标记 的下标 i 和 j ,满足 2 * nums[i] <= nums[j] ,标记下标 i 和 j 。

请你执行上述操作任意次,返回 nums 中最多可以标记的下标数目。

示例 1:

1
2
3
4
输入:nums = [3,5,2,4]
输出:2
解释:第一次操作中,选择 i = 2 和 j = 1 ,操作可以执行的原因是 2 * nums[2] <= nums[1] ,标记下标 2 和 1 。
没有其他更多可执行的操作,所以答案为 2 。

示例 2:

1
2
3
4
5
输入:nums = [9,2,5,4]
输出:4
解释:第一次操作中,选择 i = 3 和 j = 0 ,操作可以执行的原因是 2 * nums[3] <= nums[0] ,标记下标 3 和 0 。
第二次操作中,选择 i = 1 和 j = 2 ,操作可以执行的原因是 2 * nums[1] <= nums[2] ,标记下标 1 和 2 。
没有其他更多可执行的操作,所以答案为 4 。

示例 3:

1
2
3
输入:nums = [7,6,8]
输出:0
解释:没有任何可以执行的操作,所以答案为 0 。

提示:

  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^9

题解

方法一:

思路

二分+贪心。

首先如果有x对下标可以标记,肯定x-1对下标可以被标记。

所以可以在区间[0,n/2]通过二分法求出最大可标记对数。

如果当前二分的对数为k。

那么可以通过贪心来检测是否满足。

我们用最小的k个值和最大的k个值进行匹配,如果可以匹配,则增大k;
否则,减小k。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public:
int maxNumOfMarkedIndices(vector<int>& nums) {
int n = nums.size();
sort(nums.begin(), nums.end());
int l = 0, r = n/2+1;
while (l<r) {
int m = l+r>>1;
// int l1 = 0, r1 = m-1, l2 = n-m, r2 = n-1;
bool ok = 1;
for (int i=0; i<m; i++) {
if (2*nums[i]>nums[n-m+i]) {
ok = 0;
break;
}
}
if (ok) {
l = m+1;
} else {
r = m;
}
}
return 2*(r-1);
}
};