看到互不相同的元素,一定想到hash!
题目简述
n个互不相同的数,排列组合成两个序列a和b,每次操作只能从a中选择第一个或最后一个数字并插入a中任意位置,问最少需要多少次操作把a变成b。
算法分析
设n个元素为x1, x2, ..., xn,因为要从a变成b,所以把b中的值[xk1, xk2, ..., xkn]用hash_map映射为[0, 1, ..., n-1]。
那么题目就变为,把a中的映射值[i1, i2, ..., in] 变为固定值 [0, 1, ..., n-1]。
这样此题就变为求a数组中的最长上升子串问题了
C++代码
详细分析:
若 ai, ai+1, ..., aj是最长上升子串,则一定有 ai-1 > ai,aj+1 < aj, 那么前面从a0到ai-1的i个值都需要依次移动,后面从aj到an-1的n-j个值都需要依次移动。
因为我们只能每次移动首元素或者尾元素,哪怕a0到ai-2都不需要移动,我们为了移动ai-1,也只能把它们全都移动到ai-1后面,使ai-1变为首元素,从而移动ai-1到正确位置;
同理,为了移动aj+1,aj+2到an的元素无论如何都需要被移动。例如:[1,2,4,3,5,6,8,7,9,10]的最长上升子串为"3,5,6,8"
所以总的移动次数就是 n - maxlen。
#include<iostream>
#include<vector>
#include<algorithm>
#include <unordered_map>
using namespace std;
int No10_hash(vector<int>& a, vector<int>& b) {
int n = a.size();
// 1. 因为要把a编程b,所以对b做映射,b中的值[A,B,C,D] 映射为 [0,1,2,3]
unordered_map<int, int> mp;
for (int i = 0; i < n; i++) mp[b[i]] = i;
// 2. 这样把a也变成映射值后,就是让a变成[0,1,2,3]这个固定值,那就是求a的最长上升子串
int len = 0, cur = 0, curi = -1;
for (int i = 0; i < n; i++) {
if (mp[a[i]] > curi) cur++;
else {
len = max(len, cur);
cur = 1;
}
curi = mp[a[i]];
}
len = max(len, cur);
//若 ai, ai+1, ..., aj是最长上升子串
//则一定有 ai-1 > ai,aj+1 < aj,
//那么从a0到ai-1的i个值都需要依次移动,从aj到an-1的n-j个值都需要依次移动
return n - len; //所以答案为 n-len
}
int main() {
int n;
cin>>n;
vector<int> a(n, 0);
vector<int> b(n, 0);
for(int i=0; i<n; i++) cin>>a[i];
for(int i=0; i<n; i++) cin>>b[i];
cout<<No10_hash(a, b)<<'\n';
return 0;
}