问题描述
一个数组中,如果两个数的公共因子有大于1的,则认为这两个数之间有通路。返回数组中有多少独立的域。
思路
该题整体使用并查集的思想解题。
思路一: 从数组的第一个位置一次查看后面每一个位置对否两数之间有公共因子,并查集联合两个区域,最后返回并查集的个数即可。
思路二: 遍历数组中的每一个数字记该数字为n,找出1~根号n之间除1外的所有质数,并查集统计,最后返回并查集的个数即可。
代码
准备代码:
public static class UnionFindSet {
public HashMap<Integer, Integer> fatherMap;//key的父亲 value
//key是代表点的时候才有记录,value是所在集合一共有多少点
public HashMap<Integer, Integer> sizeMap;
public UnionFindSet(int size) {
fatherMap = new HashMap<>();
sizeMap = new HashMap<>();
for (int i = 0; i < size; i++) {
fatherMap.put(i, i);
sizeMap.put(i, 1);
}
}
public int size() {
return sizeMap.size();
}
public int maxSize() {
int ans = 0;
for (int size : sizeMap.values()) {
ans = Math.max(ans, size);
}
return ans;
}
private int findHead(int element) {
Stack<Integer> path = new Stack<>();
while (element != fatherMap.get(element)) {
path.push(element);
element = fatherMap.get(element);
}
while (!path.isEmpty()) {
fatherMap.put(path.pop(), element);
}
return element;
}
public void union(int a, int b) {
int aF = findHead(a);
int bF = findHead(b);
if (aF != bF) {
int big = sizeMap.get(aF) >= sizeMap.get(bF) ? aF : bF;
int small = big == aF ? bF : aF;
fatherMap.put(small, big);
sizeMap.put(big, sizeMap.get(aF) + sizeMap.get(bF));
sizeMap.remove(small);
}
}
}
//求两数的公共质数
public static int gcd(int m, int n) {
return n == 0 ? m : gcd(n, m % n);
}
思路一代码:
//arr中没有小于1的数
public static int largestComponentSize1(int[] arr) {
UnionFindSet set = new UnionFindSet(arr.length);
for (int i = 0; i < arr.length; i++) {
for (int j = i + 1; j < arr.length; j++) {
if (gcd(arr[i], arr[j]) != 1) {
set.union(i, j);
}
}
}
return set.maxSize();
}
思路二代码:
public static int largestComponentSize2(int[] arr) {
UnionFindSet unionFind = new UnionFindSet(arr.length);
//key 是某个因子
//value 是包含key因子的其中一个数的位置
HashMap<Integer, Integer> fatorsMap = new HashMap<>();
for (int i = 0; i < arr.length; i++) {
int num = arr[i];
int limit = (int) Math.sqrt(num);//1~根号num
for (int j = 1; j <= limit; j++) {//j是现在试的因子
if (num % j == 0) {//num含有j的因子
if (j != 1) {//这个因子不是1
if (!fatorsMap.containsKey(j)) {//当前数是含有j因子的第一个数
fatorsMap.put(j, i);
} else {
unionFind.union(fatorsMap.get(j), i);
}
}
int other = num / j;//other * j == num
if (other != 1) {//num含有other的因子
if (!fatorsMap.containsKey(other)) {
fatorsMap.put(other, i);
} else {
unionFind.union(fatorsMap.get(other), i);
}
}
}
}
}
return unionFind.maxSize();
}
对数器验证代码:
public static int[] generateArray(int len, int maxValue) {
int[] res = new int[len];
for (int i = 0; i < res.length; i++) {
res[i] = (int) (Math.random() * maxValue) + 1;
}
return res;
}
public static int[] copyArray(int[] arr) {
if (arr == null || arr.length == 0) {
return null;
}
int[] res = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
res[i] = arr[i];
}
return res;
}
public static void printArray(int[] arr) {
for (int i = 0; i != arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
public static void main(String[] args) {
int len = 20;
int maxValue = 30;
int testTime = 30;
System.out.println("test begin!");
for (int i = 0; i < testTime; i++) {
int[] arr1 = generateArray(len, maxValue);
int[] arr2 = copyArray(arr1);
int res1 = largestComponentSize1(arr1);
int res2 = largestComponentSize2(arr2);
if (res1 != res2) {
System.out.println("Oops!");
printArray(arr1);
printArray(arr2);
System.out.println(res1);
System.out.println(res2);
break;
}
}
System.out.println("test end!");
}