题目描述
难度分:1400
输入n(1≤n≤2×105)和两个1~n的排列a,b。
你可以对a或b执行任意次循环右移或循环左移。输出操作后,最多有多少个a[i]=b[i]。
注:把[1,2,3,4]循环右移一次,得[4,1,2,3]。
输入样例1
5
1 2 3 4 5
2 3 4 5 1
输出样例1
5
输入样例2
5
5 4 3 2 1
1 2 3 4 5
输出样例2
1
输入样例3
4
1 3 2 4
4 2 3 1
输出样例3
2
算法
分组
不是很好想,一开始没有利用a和b都是排列的特性,一直陷入“字符串匹配”的思路,怎么都做不对。最后发现利用排列这个条件很容易就能解决,如果a[i]=b[j]成立,假想a的i位置向b的j位置连了一根线,那由于a中a[i]这个数值只有一个,b中b[j]这个数值也只有一个,所以只要把相同“斜率”(斜率定义为k=val2pos1[val]−val2pos2[val],其中val2pos1[val]表示val这个数值在数组a中的索引,val2pos2[val]表示val这个数值在数组b中的索引)的线分到同一组就可以了。
由于可以对a数组进行旋转操作,负的斜率通过加上n处理成正数。所有组中,线数量的最大值就是答案。
复杂度分析
时间复杂度
遍历a和b两个数组预处理出val2pos1和val2pos2,再遍历一遍数组a进行斜率分组,时间复杂度为O(n)。
空间复杂度
val2pos1、val2pos2以及斜率分组数组cnt的空间消耗都是线性的,因此算法的额外空间复杂度为O(n)。
C++ 代码
#include <bits/stdc++.h>
using namespace std;
const int N = 200010;
int n, a[N], b[N];
int main() {
scanf("%d", &n);
int val2pos1[n] = {0};
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
val2pos1[a[i]] = i;
}
int val2pos2[n] = {0};
for(int i = 1; i <= n; i++) {
scanf("%d", &b[i]);
val2pos2[b[i]] = i;
}
int ans = 0;
int cnt[n] = {0};
for(int i = 1; i <= n; i++) {
int offset = (val2pos1[a[i]] - val2pos2[a[i]] + n) % n;
cnt[offset]++;
ans = max(ans, cnt[offset]);
}
printf("%d\n", ans);
return 0;
}