如何加速数组中可被同组元素整除元素的计数求解程序?
如何优化数组最大整除计数程序以避免超时?
问题背景
给定一个数组,找出最大计数:数组中某个元素的计数定义为数组中可以整除该元素的元素数量。例如数组[2,2,2,5,6,8,9,9]的最大计数为4,因为6或8可被2、2、2及自身整除。
原实现思路:
- 对数组排序并转换为有序集合
- 用索引对应元素值的数组记录每个元素的出现次数
- 双层循环从大到小遍历集合元素,检查与其他元素的整除性并累加计数
约束条件:1 <= arr[i] <= 10000,数组长度最多10000。
原代码通过9/10测试用例,但第10个用例超时,需要优化。
瓶颈分析
原代码的双层循环逻辑时间复杂度为O(k²)(k是集合中不同元素的数量),当k接近10000时,循环次数会达到数千万级别,远超时间限制,这是超时的核心原因。
优化方案
利用元素最大值仅为10000的特性,采用计数数组+倍数遍历的方法,时间复杂度降至O(M log M)(M=10000),效率大幅提升。
具体步骤
- 统计元素出现次数:创建大小为10001的数组
cnt,cnt[x]表示x在原数组中的出现次数。 - 动态规划计算每个元素的计数:创建
dp数组,dp[x]初始化为cnt[x](自身的数量)。从小到大遍历每个数i,若cnt[i]>0,则遍历i的所有倍数j(j=2i,3i,...,≤10000),将dp[j] += cnt[i]——因为i能整除j,所以所有i的出现次数都要计入j的计数。 - 找最大值:遍历
dp数组,取最大值即为答案。
优化后的代码
#include <stdio.h> #include <stdlib.h> #include <limits.h> int main(void) { int arr[] = {2,2,2,5,6,8,9,9}; int size = sizeof(arr)/sizeof(arr[0]); const int MAX_VAL = 10000; // 统计每个数的出现次数 int cnt[MAX_VAL + 1] = {0}; for (int i = 0; i < size; i++) { cnt[arr[i]]++; } // 计算每个数的最大计数并同步找最大值 int dp[MAX_VAL + 1] = {0}; int max_count = 0; for (int i = 1; i <= MAX_VAL; i++) { dp[i] = cnt[i]; // 遍历i的所有倍数,累加计数 for (int j = 2*i; j <= MAX_VAL; j += i) { dp[j] += cnt[i]; } // 更新全局最大值 if (dp[i] > max_count) { max_count = dp[i]; } } printf("%d", max_count); return 0; }
关键优化点说明
- 彻底避免了原代码中对集合元素的双层遍历,转而利用倍数关系直接累加,循环次数从数千万级降至1.4万级左右
- 省略了排序和转集合的步骤,直接通过一次遍历统计元素出现次数,进一步节省时间
- 最大值计算与计数计算同步进行,无需额外遍历
- 压缩了数组空间,原代码中10万大小的数组被替换为1万零1大小的数组,减少空间浪费
内容的提问来源于stack exchange,提问作者Agrudge Amicus
相关产品推荐
相关产品推荐

