原题链接
一开始兴高采烈写完,以为很简单就ac了,结果蹦出两个超时。由于我基本用的scanf,所以输入数据应该不会导致超时,一定是中间某个步骤复杂度太大导致超时了。所以我把目光放在的两个循环上。
很显然,我中间用到了两个嵌套循环,复杂度是二次方级,我需要优化一下降低复杂度。我想了很久没有想到解决的办法,觉得不历遍数组是不行的(最搞笑的是我尝试甚至还用了随机数,结果全部超时)。
后来我翻看了下算法笔记,提到利用已swap数据的不可移动性存储位置。一开始我抱有疑惑,觉得不可行,依然需要历遍数组,但后来仔细思考后发现的确是个很好的办法,并没有漏洞,并且很好地将复杂度降低了。在这里我简单总结下。
让k从1开始,向前走,慢慢递增,直到遇见第一个没有回归本位的数,再记录下来它的位置(就像是一辆车向前走,停在遇到的一个障碍上并记录位置)。在算法中我们不会在移动以归位的数字,因此已归位的数字就像平坦的路一样,车已经走过的路不会突然消失。接下来的工作就是移除障碍(就是令其归位后再令k++),车从刚刚记录的位置继续往前走,直到下一个障碍,记录,清除障碍……车不需要回到路的一开头重新开到障碍前,这就省下了很多路程。
下面给出我自己的实现代码。
#include<stdio.h>
#include<iostream>
using namespace std;
int main() {
int number = 0;
int count = 0;
int temp = 0;
int j = 0;
int k = 1;
int a[100010] = { 0 };
int hashTable[100010] = { 0 };
cin >> number;
for (int i = 0; i < number; i++) {
scanf("%d", &a[i]);
hashTable[a[i]] = i;
if (a[i] == 0)
temp = i;
}
for (int i = 0; ; i++) {
int exc = 0;
if (a[0] == 0) {
for (j = k; j < number; j++) {
if (a[j] == j)
continue;
else {
k = j + 1;
a[0] = a[j];
a[j] = 0;
count++;
temp = j;
hashTable[a[0]] = 0;
hashTable[0] = j;
break;
}
}
if (temp == 0)
break;
}
exc = hashTable[temp];
a[exc] = 0;
a[temp] = temp;
hashTable[temp] = temp;
hashTable[0] = exc;
count++;
temp = exc;
}
cout << count;
}
版权声明:本文为fire_for_you原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。