“每个人都有错,但只有愚者才会执迷不悟。”——西塞罗
题目
给你一个下标从 0 开始的整数数组 nums
。
一开始,所有下标都没有被标记。你可以执行以下操作任意次:
- 选择两个 互不相同且未标记 的下标
i
和j
,满足2 * nums[i] <= nums[j]
,标记下标i
和j
。
请你执行上述操作任意次,返回 nums
中最多可以标记的下标数目。
难度:中等
分析
笔者想到的又不是最好的方法,又一次😶。把两种方法都记录一下。
二分查找:我们假设可以进行k次操作,那么为了尽可能满足2 * nums[i] <= nums[j]
,肯定是拿nums最小的k个数字与最大的k个数字进行相应的配对,并且相对较小的与相对较小的配对。二分计算操作数,判断数组可以是否满足k次操作。
双指针:为了进行最多的配对,理想情况是拿排序后的nums的前半部分与后半部分进行配对,使用双指针,假设左半部分下标为i,右半部分下标为j,如果不满足条件,则判断后面的j。
解答
排序+二分查找
class Solution {
public:
int maxNumOfMarkedIndices(vector<int>& nums) {
int n=nums.size();
sort(nums.begin(),nums.end());
// 二分操作数
int left=0,right=n/2;
while (left<=right){
int mid=left+(right-left)/2;
if (check(nums,mid)){
left=mid+1;
}else{
right=mid-1;
}
}
return right*2;
}
bool check(vector<int>& nums, int k){
int n=nums.size();
for (int i=0;i<k;i++){
if (nums[i]*2>nums[n-k+i]){
return false;
}
}
return true;
}
};
排序+双指针
class Solution {
public:
int maxNumOfMarkedIndices(vector<int>& nums) {
int n=nums.size();
sort(nums.begin(),nums.end());
int ans=0;
int left=0,right=n/2;
while (left<n/2&&right<n){
while (right<n&&nums[left]*2>nums[right]){
right++;
}
if (right<n){
ans+=2;
right++;
}
left++;
}
return ans;
}
};