算法思路
本题不难,下面说一下解题过程中的思路。首先,题目要求只能通过0与i交换来排序,根据样例可以断定,最快的方法是将0与0当前所在位置应该放置的数进行对换。例如:
最开始 {4, 0, 2, 1, 3},0在1号位置,那么将0与1对换
Swap(0, 1) => {4, 1, 2, 0, 3}
这样,1就完成了正确的摆放位置。现在,0在3号位置,那么将0与3对换
Swap(0, 3) => {4, 1, 2, 3, 0}
这样,3也完成了正确的摆放位置。现在,0在4号位置,那么将0与4对换
Swap(0, 4) => {0, 1, 2, 3, 4}
可以看到,排序完成。如果理想的话,照这种方法,只需要n-1次对换即可完成,n为不在正确位置的元素的个数。这题初始情况下只有2在正确位置,因此n=4,需要4-1=3次对换完成排序。
但存在一种情况,即排序未完成,而0回到了正确位置。比如{1,0,3,2},第一次对换是0个1,那么现在0回到了0号位置,剩下的3和2就不能完成排序了。出现这种情况的解决方法是:当0回到0号位置,但排序未完成时,将0与任意不在正确位置的元素对换,继续上述过程。比如{1,0,3,2},经过第一次对换后变成
Swap(0, 1) => {0, 1, 3, 2}
将0和3对换,继续上述过程。当然也可以将0与2对换,继续上述过程。
代码实现思路
有了思路之后,根据思路选择恰当的数据结构并进行编码。由于很难发现上述过程简洁的数学公式,我们不如直接进行“翻译”,模拟一遍这个过程,输入对换次数即可。 在模拟过程中有几点需要注意:
一,“将0与0当前所在位置应该放置的数进行对换。”
比如0现在在3号位置,我们需要将0和3对换,但3现在在哪个位置呢?如果遍历数组进行查找,时间复杂度肯定不允许,这是可以预料到的。除了保存序列的数组外,再定义一个int pos[i],它表示等于i的元素当前所在的位置,在模拟的过程中维护这个数组,那么在需要找到任意元素的位置时,只需要O(1)时间复杂度。
但值得注意的是,pos和arr两个数组在模拟过程中要仔细维护,它们之间的关系可能有些麻烦,需要多检查几遍,耐心编码。
二,“当0回到0号位置,但排序未完成时,将0与任意不在正确位置的元素对换。”
我们需要找到任意一个还未正确摆放的元素,通过遍历数组,看元素和下标是否相等来找这个元素。定义一个函数int check(),输出第一个元素与下标不等的下标,将0与其对换。如果元素与下标都相等,代表排序完成,结束模拟过程。看似可行,但有一个测点会超时。不停的遍历数组,在机试题中肯定是不可以的。
找一个trick解决这个问题。出现这种情况,我们只需要找到任意一个不在正确位置的元素,任意,肯定不需要那么复杂。定义一个STL set容器,用来保存目前尚未在正确位置的元素。我们应该清楚的记得set常用操作的时间复杂度
插入: O(logN)
查看:O(logN)
删除:O(logN)
非常合适。在模拟过程中维护这个set,在需要找到任意一个不在正确位置的元素时,输出第一个元素即可。如果set为空,代表已完成排序,结束模拟。
代码
下面给出AC代码
#include<stdio.h>
#include<set>
using namespace std;
int arr[100000];
int pos[100000];
set<int> notSorted;
int check(int* arr, int N)
{
if (notSorted.empty() == true)
{
return -1;
}
else
{
return pos[*(notSorted.begin())];
}
}
int main()
{
int N;
scanf("%d", &N);
for (int i = 0; i < N; i++)
{
scanf("%d", &arr[i]);
pos[arr[i]] = i;
if (arr[i] != 0 && arr[i] != i)
{
notSorted.insert(arr[i]);
}
}
int ans = 0;
while (1)
{
if (pos[0] == 0)
{
pos[0] = check(arr, N);
if (pos[0] == -1)
{
break;
}
else
{
int tmp = arr[pos[0]];
arr[0] = tmp;
arr[pos[0]] = 0;
pos[tmp] = 0;
ans++;
}
}
else
{
int num = pos[0];
int posOfNum = pos[num];
arr[pos[0]] = pos[0];
arr[posOfNum] = 0;
pos[0] = posOfNum;
posOfNum = num;
notSorted.erase(num);
ans++;
}
}
printf("%d\n", ans);
return 0;
}