报告错误
如果你发现该网页中存在错误/显示异常,可以从以下两种方式向我们报告错误,我们会尽快修复:
- 使用 CS Club 网站错误 为主题,附上错误截图或描述及网址后发送邮件到 286988023@qq.com
- 在我们的网站代码仓库中创建一个 issue 并在 issue 中描述问题 点击链接前往Github仓库
题目描述
题目给一个数字N,并且给一个长N长度的字符串,求最小的操作步骤将其变成回文。你可以做以下的操作:
选取一组数字(X,Y)并将字符串种所有的X替换成Y。这个算是为一次操作
例子
8
1 5 3 2 5 2 3 1
然后我将所有的3换成2
再将所有的2换成5
就会有1 5 5 5 5 5 5 1
思路
可以用UFDS将每一组的数union起来
比如说
a b c d e f g
a-g
b-f
c-e
总共将这一棵树的节点总数-1就是这一棵树的最优解
原因是如果是在这一棵树里面的所有数都必须要与树里面的任意一个数相等,所以是变换N-1次。
然后将每一棵树的最优解相加就是答案
复杂度
step1 遍历数组, O(N);
step2 建立ufds时的union与findroot的复杂度为O(N);(给代码做了优化(path compression) 之后可以将平均复杂度降为O(1))
step3 最后遍历ufds的复杂度O(N);
所以总体复杂度为O(N);
代码实现
import java.util.*;
import java.io.*;
public class kaibun{
public static void main (String [] args){
Scanner in = new Scanner(System.in);
int length = in.nextInt();
int [] arr = new int [length];
for (int i = 0; i < arr.length; i++) {
arr[i] = in.nextInt();
}
length/=2;
//take left and right into the two arrays
int [] left = new int [length];
int [] right = new int [length];
for (int i = 0; i < length; i++) {
left[i] = arr[i];
}
int index = 0;
for( int i = arr.length-1;i>arr.length-length-1;i--){
right[index] = arr[i];
index++;
}
//System.out.println(Arrays.toString(left));
//System.out.println(Arrays.toString(right));
UFDS find = new UFDS(200005);
for (int i = 0; i < right.length; i++) {
find.union(right[i], left[i]);
}
HashMap< Integer, Long> count = new HashMap<Integer,Long>();
for ( int i = 0;i<find.ufds.length;i++){
int root = find.ufds[i];
if(i!=root){
if(count.get(root)!=null){
count.put(root, (long)count.get(root)+1L);
}else{
count.put(root, 1L);
}
}
}
long result = 0;
for ( long value : count.values()){
result+=value;
}
System.out.println(result);
}
}
class UFDS{
int [] ufds;
//union by rank
int [] rank;
public UFDS(int n){
this.ufds = new int [n];
this.rank = new int [n];
for ( int i = 0;i<ufds.length;i++) {
this.ufds[i] = i;
this.rank[i] = 0;
}
}
public void union(int u , int v){
int rootU = this.findTheRoot(u);
int rootV = this.findTheRoot(v);
if(this.rank[u]<=this.rank[v]){
if (rootU!=rootV) this.ufds[rootU] = rootV;
this.rank[rootV]++;
}else{
if(rootU!=rootV) this.ufds[rootV] = rootU;
this.rank[rootU]++;
}
}
public int findTheRoot( int n){
int ini = n;
while(n!=this.ufds[n]) n = this.ufds[n];
this.ufds[ini] = n;
return n;
}
public boolean find(int u,int v){
return findTheRoot(u)==findTheRoot(v);
}
public String toString(){
return Arrays.toString(this.ufds);
}
}