问题描述
小R有一个长度为 n
的排列,排列中的数字是 1
到 n
的整数。她每次操作可以选择两个数 a_i
和 a_j
进行交换,前提是这两个数的下标 i
和 j
的奇偶性相同(即同为奇数或同为偶数)。小R希望通过最少的操作使数组变成升序排列。
请你帮小R计算,最少需要多少次操作才能使得数组有序。如果不能通过这样的操作使数组有序,则输出 -1
。
测试样例
样例1:
输入:
n = 5, a = [1, 4, 5, 2, 3]
输出:
2
样例2:
输入:
n = 4, a = [4, 3, 2, 1]
输出:
-1
样例3:
输入:
n = 6, a = [2, 4, 6, 1, 3, 5]
输出:
-1
题解:
发现,如果原数组从0下标开始,则偶数下标必须是奇数,奇数下标必定是偶数,如果奇偶混合,则必定不能排成,返回-1。
将奇数和偶数分别进入一个数组,发现,如果从下标1开始计数,则偶数数列中,a[i]/2必定等于自己的下标,奇数数列则是(a[i]+1)/2。
分别遍历两个数组,遇到和自己下标不匹配的数,就交换位置,并且重新检测当前位置(防止出现一次交换后仍然不匹配)。
代码:
cpp
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iomanip>
#include<queue>
#include<stack>
#include<vector>
#include<unordered_set>
#include<unordered_map>
#include<map>
#include<set>
using namespace std;
typedef long long int ll;
int solution(int n, vector<int> a) {
vector<int> ji;
vector<int> ou;
ji.push_back(0);
ou.push_back(0);
for(int i=0;i<a.size();i++){
if(i%2==0 && a[i]%2==1){
ji.push_back(a[i]);
}
else if(i%2==1 && a[i]%2==0){
ou.push_back(a[i]);
}
else{
return -1;
}
}
int cnt=0;
for(int i=1;i<ji.size();i++){
if((ji[i]+1)/2 != i){
int t=ji[(ji[i]+1)/2];
ji[(ji[i]+1)/2]=ji[i];
ji[i]=t;
cnt++;i--;
}
}
for(int i=1;i<ou.size();i++){
if((ou[i])/2 != i){
int t=ou[ou[i]/2];
ou[ou[i]/2]=ou[i];
ou[i]=t;
cnt++;i--;
}
}
return cnt;
}
int main() {
vector<int> a1 = {1, 4, 5, 2, 3};
cout << (solution(5, a1) == 2) << endl;
vector<int> a2 = {4, 3, 2, 1};
cout << (solution(4, a2) == -1) << endl;
vector<int> a3 = {2, 4, 6, 1, 3, 5};
cout << (solution(6, a3) == -1) << endl;
}