A1067
思路与注意点
整体思路:数字0在i号位,找到数字i与数字0交换位置
贪心策略:本题中,如果当前 0 处于 i 号位,则找到数字 i 当前所处的位置,然后把 0 与 i 进行交换,此时数字i 就位于它的最终位置上,取得了最优解。
Questions:
1、使用哪种数据结构进行存储可以使代码编写更简洁,查找效率更高
2、一旦当0回到0号位时,此时要如何处理
3、如何判断已经有序,算法结束
Answers:
1、充分利用数组下标与数组存储值:pos[]含义,数字所处的位置(如第一个数据数字3,num = 3, pos[3] = 0,表示3这个数字位于0号位)
2、此时与数组内没有回到自己位置的任意数字交换即可打破僵局
3、预处理得到不在本位的数字的个数cnt,每次交换可确定一个数字的位置,cnt–,指导cnt不大于0,从而标志算法结束
个人做题时的思路
我个人思路与书上思路不大相同,使用arr[]存原序列,ans[]数组存已经排好序的序列。想要时刻标记出index0的位置,用arr[]中0的位置与已经排好序的ans[]中对应位置进行比对,若不相同,则在arr[]找到与ans[]中相同的数进行交换
耗时较多的地方:在arr[]中找到对应数字,判断算法结束与否
思考:有没有以空间换时间的方法提高查找效率
方法目标:0与一个数字交换,如何能快速知道,该数字究竟在几号位?
方法:设置散列,记录数字位置编号,即书中的思路
PS:
个人思路得代码显得冗余,若无时间的严格要求,个人思路能通过。
本题的两个特殊之处,输入序列范围刚好在0~N-1之间,且要求排列顺序是递增的,与数组下标一致,所有应该充分利用数组下标与数组存储的关系
代码
#include <bits/stdc++.h>
using namespace std;
int N, ans, cnt;
int pos[100005];
bool cmp(int a, int b)
{
return a < b;
}
void swaparr(int &a, int &b)
{
int temp = a;
a = b;
b = temp;
}
int main(int argc, char *argv[]) {
scanf("%d", &N);
cnt = N - 1;//记录0以外不在本位的个数,即数字未出现在对的位置
for(int i = 0; i < N; i++)
{
int num;
scanf("%d", &num);
//如:3这个数字出现在0号位上
pos[num] = i;//存放当前数字出现在几号位上,即数组的下标
if(num == i && num != 0)//当对的数字出现在对的位置,如3在3号位上时
{
cnt--;
}
}
int index = 1;
while(cnt > 0)
{
if(pos[0] == 0)//如果0在0号位上
{
while(index < N)
{
if(pos[index] != index)
{
swaparr(pos[0], pos[index]);
ans++;
//cnt--;//此处只是找到任一个不在本位上的数进行交换,并不能保证一定会换回到正确位置
break;
}
index++;
}
}
while(pos[0] != 0)
{
swaparr(pos[0], pos[pos[0]]);
ans++;
cnt--;
}
}
printf("%d", ans);
return 0;
}