一个数组中,如果两个数的公共因子有大于1的,则认为这两个数之间有通路。返回数组中有多少独立的域。

问题描述

        一个数组中,如果两个数的公共因子有大于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!");
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值