Leetcode问题转换-置换
置换是一个排列到另一个排列的双射。例如
\[\left(\begin{array}{cccccc}
x & 2 & 0 & 1 & 3 \\
P(x) & 1 & 2 & 3 & 4
\end{array}\right)
\]
将这个置换应用于另一个数组\([0,1,2,3]\)上,其就变成了\([2, 3, 1, 4]\).
置换保证了对于\(num_1\) 和 \(num_2\)中的相同元素,在置换后仍然是相同的,且元素的位置仍然是不变的,因此也不会影响答案。
好处是,通常我们可以将一个数组固定成有序的,对另一个进行统计即可。
这种题目的特征是:两个数组,且至少其中一个数组元素是互异的.
LC 1713. 得到子序列的最少操作次数
题解:本来是求两个数组的最长公共子序列,但是其中一个是互异的,因此将其置换到\(1...n\),因此题目转化为求另一个数组(经过相同置换后)的最长上升子序列。
const int INF = 0x3f3f3f3f;
class Solution {
public:
int minOperations(vector<int>& target, vector<int>& arr) {
unordered_map<int, int>mp;
int cnt = 0;
for(int num : target) mp[num] = (++cnt);
vector<int>myarr;
for(int& num : arr) {
if(mp[num]) myarr.push_back(mp[num]);
}
int n = arr.size();
vector<int>dp(n, INF);
for(int num : myarr) {
*lower_bound(dp.begin(), dp.end(), num) = num;
}
int lis = lower_bound(dp.begin(), dp.end(), INF)-dp.begin();
return target.size() - lis;
}
};
LC 2179. 统计数组中好三元组数目
题解:也是将其中一个置换到\(1...n\),对另一个使用相同的置换,然后用数组统计\(y\)左边有多少个小于其的\(x\)
const int maxn = 1e5+5;
class Solution {
public:
int n;
int c[maxn]; // [1...n]
int lowbit(int x) {
return x & (-x);
}
void add(int x, int val) {
while(x <= n) {
c[x] += val;
x += lowbit(x);
}
}
int sum(int x) { // [1..x]的和
int res = 0;
while(x > 0) {
res += c[x];
x -= lowbit(x);
}
return res;
}
long long goodTriplets(vector<int>& nums1, vector<int>& nums2) {
n = nums1.size();
int convert[n+1], id = 0;
for(int num : nums1) convert[num] = (++id);
for(int& num : nums2) num = convert[num];
long long ans = 0;
for(int i = 0;i < n;i++) {
add(nums2[i], 1);
int less = sum(nums2[i]-1);
ans += 1ll*less * (n-nums2[i]-(i-less));
}
return ans;
}
};
个性签名:时间会解决一切