📜  根据给定条件将一个排列转换为另一个排列所需的最小相邻交换次数(1)

📅  最后修改于: 2023-12-03 15:40:28.275000             🧑  作者: Mango

题目描述

给定一个长度为 $n$ 的排列 $p$ 和一个长度相等的排列 $q$,现在你可以对排列 $p$ 进行任意次如下操作:

选择排列 $p$ 中的一个位置 $i$,然后交换 $p_i$ 和 $p_{i+1}$ 的位置。

你希望将排列 $p$ 变成排列 $q$,现在请你计算出最少需要进行多少次操作可以完成这个目标。

输入格式

第一行一个整数 $n$,表示排列的长度。

第二行 $n$ 个空格隔开的整数 $p_i$,表示排列 $p$。

第三行 $n$ 个空格隔开的整数 $q_i$,表示排列 $q$。

输出格式

输出一个整数,表示最少操作次数。

数据范围

$1 \leq n \leq 1000$,$p_i$ 和 $q_i$ 均为 $1$ 到 $n$ 之间的整数。

输入样例
5
1 2 3 5 4
5 2 3 4 1
输出样例
2
算法分析

本道题我们采用贪心和双指针算法来解决。我们先找出两个排列中相同数字的位置,假如相同数字在位置 $a,b$ 和 $c,d$ 分别出现,我们可以通过 $2$ 次操作,使得 $a,b$ 前的数字和 $c,d$ 前的数字分别相同,之后问题就被分解成了规模更小的子问题,由于一些限制,我们又发现了新的贪心策略,使得 $O(n^2)$ 的时间复杂度可以优化至 $O(n \log n)$ 的时间复杂度,详情请看下面的代码实现。此外要注意,题目数据范围比较小,不能直接使用归并排序,否则会超时,应该手写归并排序来避免 TLE。

python 代码实现
n = int(input())
p = list(map(int, input().split()))
q = list(map(int, input().split()))

locx = [0] * (n + 1)
locy = [0] * (n + 1)

for i in range(n):
    locx[p[i]] = i
    locy[q[i]] = i

cnt = 0

for i in range(1, n + 1):
    while locx[i] != locy[i]:
        j = locy[i]
        k = p[j - 1]
        locx[k], locx[k + 1], locx[i] = locx[k + 1], locx[k], j - 1
        p[j - 1], p[j] = p[j], p[j - 1]
        cnt += 1

print(cnt)
C++ 代码实现
#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const int N=1e5+10, M=1e6+10;
const int INF=0x3f3f3f3f;
int n, a[N], b[N], pa[N], pb[N], res;

void merge_sort(int l, int r)
{
    if(l>=r) return ;
    int mid=l+r>>1;
    merge_sort(l, mid), merge_sort(mid+1, r);
    int i=l, j=mid+1, idx=l;
    while(i<=mid && j<=r)
        if(a[i]<=a[j]) pb[idx]=pa[i], b[idx++]=a[i++];
        else pb[idx]=pa[j], b[idx++]=a[j++];
    while(i<=mid) pb[idx]=pa[i], b[idx++]=a[i++];
    while(j<=r) pb[idx]=pa[j], b[idx++]=a[j++];
    for(int i=l; i<=r; i++) a[i]=b[i], pa[i]=pb[i];
}

int main(void)
{
    scanf("%d", &n);
    for(int i=1; i<=n; i++)
    {
        scanf("%d", &a[i]);
        pa[i]=i;
    }
    res=0;
    merge_sort(1, n);
    for(int i=1; i<=n; i++)
        if(pa[i]!=i)
        {
            res++;
            swap(pa[i], pa[a[i]]);
            //printf("%d %d\n", i, a[i]);
            swap(a[i], a[pa[i]]);
        }
    printf("%d\n", res);
    return 0;
}