PAT 1067 贪心

题目

给定一个序列,序列里面的数字范围是 0 ~ N - 1,要求只能交换数字0的情况下,交换几次可以使得整个序列有序

代码和思路

  1. 因为数字范围是0 ~ N - 1,所以每个位置下标就是这个位置应该对应的数字
  2. 因为要交换,最优的操作是每一步都让0和0所对应的下标的数字进行交换
  3. 但如果这样做,每次都要去找到0,和0的下标所对应的数的位置,寻找的时间复杂度是O(N),而且这样的操作执行次数也是O(N)级别的,整体就会是O(N2)级别,所以只要做到每一次都让对应的数字归位,我们可以就在pos[0]上操作,使得pos[0]上的数字直接和pos[pos[0]]上的数字进行交换
  4. 但这样就会产生一个问题,如果0回到了0,那么就不能交换了,所以必须将0和一个不在其位置上的数进行一次无效交换,使得上述操作可以继续进行
  5. 因为归位后的数字一定不会参与和0的上述无效交换,但如果每次遇到了pos[0] = 0都去遍历整个数组去找一个不在本位上的数,开销太大了。可以一开始定义一个变量k(生存域是整个函数),来记录不在本位上的最小位置(最小下标),k可以确保曾经遍历过的数不会再去遍历一次(有点动态规划的感觉)
  6. 最后就是跳出循环的问题,因为我们只执行了交换操作,而从整体上来看,我们并不知道什么时候有序,所以要在读入的时候记录一下不在本位上的数的个数作为循环跳出条件
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 100010;

int pos[maxn];

int main() {
	int n, ans = 0;
	int k = 1;
	scanf("%d", &n);
    int left = n - 1;
	for (int i = 0; i < n; i++) {
		scanf("%d", &pos[i]);
		if (pos[i] == i && i != 0) {
			left--;
		}
	}
	while (left > 0) {
		if (pos[0] == 0) {
			while (k < n) {
				//k来记录最小的不在本位上的数,这样以后再使用的时候不用重复遍历
				//有点动态规划的感觉
				if (pos[k] != k) {
				//这里不能k++,因为交换以后,并没有确定k位置上的数字回归本位
				//k下标所对应的数仍然是一个未知情况
					swap(pos[0], pos[k]);
					ans++;
					break;
				}
				k++;
			}
		}
		while (pos[0] != 0) {
			swap(pos[0], pos[pos[0]]);
			ans++;
			left--;
		}
	}
	printf("%d", ans);
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值