题目描述:给定两个数组A和B,A和B的元素相同,顺序不同,并且一个数组中的元素没有重复,删除最少的元素,使A和B元素个数与顺序相同。例如A={1,3,5,2},B={3,2,1,5},删除3和2之后A数组与B数组元素个数与顺序相同(元素个数小于100000)。
思路:找出A和B的最长公共子序列,删除其余元素即可。
需要注意的点:元素个数100000级别,如果写O(n^2)的最长公共子序列算法,时间太久,因此需要考虑O(nlogn)的算法。
解答:元素没有重复,因此可以转换为最长递增子序列求解,以下:
A数组映射为1,2,3,4,...;B数组根据A数组的映射关系转换(B元素在A数组中的位置);B数组计算最长递增子序列。
//最长递增子序列
public static int LIS(int[] A, int n) {
int[] B = new int[n+1]; B[1] = A[0];
int len=1,start=0,end=len,mid;
for(int i = 1;i<n;i++){
if(A[i]>B[len]) {len++;B[len] = A[i];}
else{
start=1;end=len;
while(start<=end){
mid=(start+end)/2;
if(B[mid]<A[i]) start=mid+1;
else end=mid-1;
} B[start] = A[i];
}
}
return len;
}
//最长公共子序列
public static int LCSNLogN(int[] A,int[] B, int n){
if(A==null||A.length<=0||n<=0||A.length!=n) return 0;
LinkedHashMap<Integer,Integer> mapDict=new LinkedHashMap<>();
int[] data=new int[n];
for(int i=0;i<n;i++){
mapDict.put(A[i],i);
}
for(int i=0;i<n;i++){
data[i]=mapDict.get(B[i]);
}
return LIS(data,n);
}
另附:
LIS的代码借用这位老哥的博客中O(nlogn)的代码,如有不妥请联系删除:https://blog.csdn.net/karute/article/details/80761957
常规的动态规划O(n^2)算法:https://blog.csdn.net/qq_26567507/article/details/82712103