题目描述:
给你一个下标从 0 开始的整数数组 nums
。
一开始,所有下标都没有被标记。你可以执行以下操作任意次:
- 选择两个 互不相同且未标记 的下标
i
和 j
,满足 2 * nums[i] <= nums[j]
,标记下标 i
和 j
。
请你执行上述操作任意次,返回 nums
中最多可以标记的下标数目。
数据范围:
$1\le nums.len \le 10^5,1\le nums[i] \le 10^9$
题解:
二分check:
满足二分单调性,对数越少越容易满足,越多越不容易满足。对于 $mid$ 对,需要检查最小的 $mid$ 个数与最大的 $mid$ 个数是否能够匹配。
每一个都需要检查。
双指针:
最大的答案就是 $n / 2$ ,前一半与后一半匹配。找到第一个数 $i = 0$ 需要匹配的 $j$ ,然后 $i + 1$ 需要匹配 $j$ 后面的数。可以直接双指针实现。
代码:
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| auto optimize_cpp_stdio = []() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::cout.tie(nullptr); return 0; }(); class Solution { public: const static int maxn = 1e5 + 10; const static int maxm = 1e5 + 10; const int INF = 0x3f3f3f3f; bool check(int mid, vector<int> &nums) { int n = nums.size(); for (int i = 0, j = n - mid + i; i < mid; ++i, ++j) { if(nums[i] * 2 > nums[j]) return false; } return true; } int maxNumOfMarkedIndices(vector<int> &nums) { sort(nums.begin(), nums.end()); int n = nums.size(); int l = 1, r = n / 2; int ans = 0; while (l <= r) { int mid = (l + r) >> 1; if (check(mid, nums)) { ans = mid * 2; l = mid + 1; } else { r = mid - 1; } } return ans; } };
|
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 26 27 28 29 30 31 32 33
| auto optimize_cpp_stdio = []() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::cout.tie(nullptr); return 0; }(); class Solution { public: const static int maxn = 1e5 + 10; const static int maxm = 1e5 + 10; const int INF = 0x3f3f3f3f; int maxNumOfMarkedIndices(vector<int> &nums) { sort(nums.begin(), nums.end()); int n = nums.size(); int l = 0, r = (n + 1) / 2; int ans = 0; while (r < n) { if (nums[l] * 2 > nums[r]) ++r; else { ++l; ++r; ans += 2; } } return ans; } };
|