题目描述
牛客幼儿园的小朋友课间操时间需要按照学号从小到大排队,但是他们太小了只能站成一列顺序却不对,现在幼儿园的阿姨需要帮忙交换小朋友的位置让他们最终有序,阿姨希望能尽快完成交换操作,问最少需要交换多少次,才能使得小朋友们从小到大排好。
注意:每个小朋友的学号不同,但是未必连续,因为可能有小朋友请假了没有来。
输入描述:
第一行一个整数 N。
接下来 N 行每行一个整数,为小朋友们的队列。
输出描述:
一个整数表示小朋友们的最小交换次数。
示例1
输入
复制
3
2
1
3
输出
复制
1
备注:
N≤100000,其他整数均≤109N\leq100000,其他整数均\leq 10^{9}N≤100000,其他整数均≤109
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
vector<int> nums;
ll getMinSwaps(vector<int> &A)
{
// 排序
vector<int> B(A);
sort(B.begin(), B.end());
map<int, int> m;
ll len = (int)A.size();
for (int i = 0; i < len; i++)
{
m[B[i]] = i; // 建立每个元素与其应放位置的映射关系
}
ll loops = 0; // 循环节个数
vector<bool> flag(len, false);
// 找出循环节的个数
for (int i = 0; i < len; i++)
{
if (!flag[i])
{
int j = i;
while (!flag[j])
{
flag[j] = true;
j = m[A[j]]; // 原序列中j位置的元素在有序序列中的位置
}
loops++;
}
}
return len - loops;
}
int main()
{
int n, t;
cin >> n;
for(int i = 0; i < n; ++i) {
scanf("%d", &t);
nums.push_back(t);
}
cout << getMinSwaps(nums) << endl;
return 0;
}
暴力模拟
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<map>
#include<string.h>
using namespace std;
const int N = 1e6 + 10;
int s[N];
int so[N];
map<int, int>p;
int main()
{
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++)scanf("%d", &s[i]);
memcpy(so, s, sizeof s);
sort(so, so + n);
for (int i = 0; i < n; i++)p[so[i]] = i; int num = 0;
for (int i = 0; i < n; i++)
{
if (p[s[i]] != i)
{
while (p[s[i]] != i)
{
swap(s[i], s[p[s[i]]]);
num++;
}
}
}
printf("%d", num);
}