设为首页 加入收藏

TOP

LeetCode952三部曲之三:再次优化(122ms -> 96ms,超51% -> 超91%)(二)
2023-09-09 10:25:53 】 浏览:54
Tags:LeetCode952 122ms 96ms 51% 91%
] primes = new int[100001]; // 素数的数量,也就是primes中有效数据的长度 private static int primeNum = 0; static { // 欧拉筛 for(int i=2;i<=100000;i++) { if(isPrime[i]==0) { // i是素数,就放入primes数组中 // 更新primes中素数的数量 primes[primeNum++] = i; System.out.println(i + "-" + i*i); } for(int j=0;i*primes[j]<=100000;j++) { // primes[j]*i的结果是个乘积,这样的数字显然不是素数,所以在isPrimes数组中标注为1 isPrime[primes[j]*i] = 1; // 如果i是primes中某个素数的倍数,就没有必要再计算了,退出算下一个, // 例如i=8的时候,其实在之前i=4时就已经计算出8不是素数了 if(i%primes[j]==0) { break; } } } // 经过以上代码,0-100001之间所有素数都放入了primes中 } /** * 带压缩的并查集查找(即寻找指定数字的根节点) * @param i */ private int find(int i) { // 如果执向的是自己,那就是根节点了 if(fathers[i]==i) { return i; } // 用递归的方式寻找,并且将整个路径上所有长辈节点的父节点都改成根节点, // 例如1的父节点是2,2的父节点是3,3的父节点是4,4就是根节点,在这次查找后,1的父节点变成了4,2的父节点也变成了4,3的父节点还是4 fathers[i] = find(fathers[i]); return fathers[i]; } /** * 并查集合并,合并后,child会成为parent的子节点 * @param parent * @param child */ private void union(int parent, int child) { int parentRoot = find(parent); int childRoot = find(child); // 如果有共同根节点,就提前返回 if (parentRoot==childRoot) { return; } // child元素根节点是childRoot,现在将childRoot的父节点从它自己改成了parentRoot, // 这就相当于child所在的整棵树都拿给parent的根节点做子树了 fathers[childRoot] = fathers[parentRoot]; // 合并后,这个树变大了,新增元素的数量等于被合并的字数元素数量 rootSetSize[parentRoot] += rootSetSize[childRoot]; // 更像最大数量 maxRootSetSize = Math.max(maxRootSetSize, rootSetSize[parentRoot]); } public int largestComponentSize(int[] nums) { // 对数组中的每个数,算出所有质因数,构建map for (int i=0;i<nums.length;i++) { int cur = nums[i]; // cur的质因数一定是primes中的一个 for (int j=0;j<primeNum && primes[j]*primes[j]<=cur;j++) { if (cur%primes[j]==0) { map.computeIfAbsent(primes[j], key -> new ArrayList<>()).add(i); // 要从cur中将primes[j]有关的倍数全部剔除,才能检查下一个素数 while (cur%primes[j]==0) { cur /= primes[j]; } } } // 能走到这里依然不等于1,是因为for循环中的primes[j]*primes[j]<<=cur导致了部分素数没有检查到, // 例如6,执行了for循环第一轮后,被2除过,cur等于3,此时j=1,那么primes[j]=3,因此 3*3无法小于cur的3,于是退出for循环, // 此时cur等于3,应该是个素数,所以nums[i]就能被此时的cur整除,那么此时的cur就是nums[i]的质因数,也应该放入map if (cur>1) { map.computeIfAbsent(cur, key -> new ArrayList<>()).add(i); } } fathers = new int[nums.length]; rootSetSize = new int[nums.length]; // 至此,map已经准备好了,接下来是并查集的事情,先要初始化数组 for(int i=0;i< fathers.length;i++) { // 这就表示:数字i的父节点是自己 fathers[i] = i; // 这就表示:数字i加上其下所有子节点的数量等于1(因为每个节点父节点都是自己,所以每个节点都没有子节点) rootSetSize[i] = 1; } // 遍历map for (int key : map.keySet()) { // 每个key都是一个质因数 // 每个value都是这个质因数对应的数字 List<Integer> list = map.get(key); int size = list.size(); // 超过1个元素才有必要合并 if (size>1) { // 取第0个元素作为父节点 int parent = list.get(0); // 将其他节点全部作为地0个元素的子节点 for(int i=1;i<size;i++) { union(parent, list.get(i)); } } } return maxRootSetSize; } }
  • 改动完成,提交试试,如下图,左边是前文的成绩,右边是本次优化后的成绩,从122ms优化到96ms,从超51%优化到超91%,优化效果明显

在这里插入图片描述

  • 至此,《LeetCode952三部曲》全部完成,如果您正在刷题,希望此系列能给您一些参考

欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

欢迎关注博客园:程序员欣宸

学习路上,你不孤单,欣宸原创一路相伴...05086920)

首页 上一页 1 2 下一页 尾页 2/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇前瞻|Java 21 新特性 String Tem.. 下一篇JAVA第一课——初识HTML

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目