题目
给定一个长度为偶数的整数数组 arr,只有对 arr 进行重组后可以满足 “对于每个 0 <= i < len(arr) / 2,都有 arr[2 * i + 1] = 2 * arr[2 * i]” 时,返回 true;否则,返回 false。
示例 1:
输入:arr = [3,1,3,6]
输出:false
示例 2:
输入:arr = [2,1,2,6]
输出:false
示例 3:
输入:arr = [4,-2,2,-4]
输出:true
解释:可以用 [-2,-4] 和 [2,4] 这两组组成 [-2,-4,2,4] 或是 [2,4,-2,-4]
提示:
- 0 <= arr.length <= 3 * 104
- arr.length 是偶数
- -105 <= arr[i] <= 105
答案
解
题目可理解为将一个数组分割成两个数组,其中一个数组的所有元素*2等于另一个数组,可先对原数组进行自定义排序,随后用双指针的方式挑选出大小关系为2倍的数字。自定义排序用于保证对于[2, 4, 1, 8]这种情况2与4不会先于1与2进行配对,同时绝对值保证对于[-2,-4]这种情况排序后-2排在-4前,负数小于正数/负数大于正数用于保证一次配对后end指针不会从头重新遍历。
class Solution {
public:
bool canReorderDoubled(vector<int>& arr) { //双指针
sort(arr.begin(),arr.end(), [](int v1, int v2){ //自定义排序,先按正负数排大小,再按照数的绝对值排大小
if(v1 == v2) //相等必须返回false,不然会溢出 https://blog.csdn.net/albertsh/article/details/119523587
return false;
else if(v1<=0 && v2>=0)
return true;
else if(v1>=0 && v2<=0)
return false;
else {
return fabs(v1) <= fabs(v2);
}
});
// for(int i=0;i<arr.size();i++)
// cout << arr[i] << " ";
vector<bool> ismarked = vector<bool>(arr.size(), false); //判断是否已用于之前的组合
int front = 0, end = 1;
while(front < end && end < arr.size()) {
if(ismarked[front]==true) { //如果当前值被使用过则跳过
front++;
if(front >= end) { //front < end
end++;
}
}
else if(ismarked[end]==true) { //如果当前值被使用过则跳过
end++;
}
else if(2 * arr[front] == arr[end]) { //如果两个值都未使用过,且成二倍关系则两者配对,指针均后移。
ismarked[front] = true;
ismarked[end] = true;
front++;
end++;
}
else { //如果两个值不成2倍关系,则end向后面查找,排序后前面一定不存在未配对的元素与arr[front]成2倍关系的情况
end++;
}
}
for(int i=0;i<ismarked.size();i++) { //如果全部被标记,即被配对则true,否则false
if(ismarked[i]==false)
return false;
}
return true;
}
};