CF-187A-Permutations
Happy PMP is freshman and he is learning about algorithmic problems. He enjoys playing algorithmic games a lot.
One of the seniors gave Happy PMP a nice game. He is given two permutations of numbers 1 through n and is asked to convert the first one to the second. In one move he can remove the last number from the permutation of numbers and inserts it back in an arbitrary position. He can either insert last number between any two consecutive numbers, or he can place it at the beginning of the permutation.
Happy PMP has an algorithm that solves the problem. But it is not fast enough. He wants to know the minimum number of moves to convert the first permutation to the second.
Input
The first line contains a single integer n (1 ≤ n ≤ 2·105) — the quantity of the numbers in the both given permutations.
Next line contains n space-separated integers — the first permutation. Each number between 1 to n will appear in the permutation exactly once.
Next line describe the second permutation in the same format.
Output
Print a single integer denoting the minimum number of moves required to convert the first permutation to the second.
Sample Input
Input
3
3 2 1
1 2 3
Output
2
Input
5
1 2 3 4 5
1 5 2 3 4
Output
1
Input
5
1 5 2 3 4
1 2 3 4 5
Output
3
这道题大意为从后边不断往前移动数据,一直将第一个序列变为第二个序列为止所需要的最少的步骤。
先上代码:
#include <stdio.h>
#define _MAX 100001
int main()
{
int A[_MAX], B[_MAX];
int N, i = 0, j = 0, count = 0, k;
scanf("%d", &N);
for (; i < N; i++)
{
scanf("%d", &A[i]);
}
for (; j < N; j++)
{
scanf("%d", &B[j]);
}
// for (i = 0; i < N; i++)
// {
// if (A[i] != B[i])
// {
// for (j = i + 1; j < N; j++)
// {
// if (A[j] == B[i])
// {
// count++;
// temp = A[j];
// for (k = j; k > i; k--)
// {
// A[k] = A[k - 1];
// }
// A[i] = temp;
// i--;
// }
// }
// }
// }
for (i = 0, j = 0; i < N && j < N; )
{
if (A[i] == B[j])
{
i++;
j++;
}
else if (A[i] == -1)
{
i++;
}
else
{
for (k = i + 1; k < N; k++)
{
if (A[k] == B[j])
{
count++;
A[k] = -1;
j++;
break;
}
}
}
}
printf("%d\n", count);
return 0;
}
注释掉的那种是一定错的,因为是暴力解题,所以会超时,没有注释掉的这种方法是以两个序列不断互相比较和向后推移下标。
但是不知为何这种写法理论上是可行的,但是依然不对,据我估计应该是超时导致的,或者就是数组开的有点小,毕竟也是O(n^2)的复杂度。
于是找到一种比较稀奇的算法,有些难于理解,但是真的很巧妙,先上代码。
#include <stdio.h>
int main()
{
int n, a[200010], b[200010], i, j, k, flag;
scanf("%d", &n);
k = -1;
for(i = 0; i < n; i++)
scanf("%d", &a[i]);
for(i = 0; i < n; i++)
scanf("%d", &b[i]);
for(i = 0; i < n; i++)
{
flag = 0;
for(j = k + 1; j < n; j++)
{
if(a[i] == b[j])
{
flag = 1;
k = j;
break;
}
}
if(!flag)
break;
}
printf("%d\n", n - i);
}
从时间复杂度上讲,同样也是O(n^2),但是这个时间复杂度的系数比较小,相比上一个算法要快捷许多,所以不会超时,当然是在数据范围内。
我们来解释一下最后一种算法,这里第一和第二个序列只会被查找一遍,(而前边一种,第一个序列会被查找很多遍),我们遇见a[i] == b[j]则说明这个数可以不用移动或者可以通过被其他数主动移动而被动的移动到自己该处在的位置,如果不想等,那么说明他所处的位置在自己应该处的位置的后边,那就必须前移。例如:1 5 2 3 4和1 2 3 4 5这个数据,1处于正确的位置(b中1的位置),不用移动,5处于正确的位置的(b中5的位置)前边,所以可以通过别的数据的移动来被推移到正确的位置,2处于正确的位置后边,所以需要移动,同理3和4都需要移动,所以最后我们可以得到有i个数据不用自己主动移动。
Ps:移动分为两种,主动移动和被动移动,主动移动是通过自己的前移来改变自己的位置,被动移动是通过别的数据前移至自己的前方而导致自己后移。也可以理解为,主动向前移动,被动向后移动。
OVER!!!