You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何统计数组中可被至少一个其他元素整除的元素数量?求最优解

如何高效找出数组中能被至少一个其他元素整除的元素数量?

嘿,这个问题我之前也碰到过,暴力法嵌套循环(挨个检查每个元素是否能被其他元素整除)的O(n²)时间复杂度,在数组规模变大的时候简直没法用。咱们来聊聊更优的解法,时间复杂度能做到O(M log M),其中M是数组中的最大值,比暴力法高效太多!

核心思路

  1. 统计元素频率:先搞清楚数组里每个数字出现了多少次,用一个频率数组(或者哈希表)来存,这样能快速判断某个数字是否存在于数组中。
  2. 遍历倍数标记符合条件的元素:找到数组中的最大值max_num,因为任何数的倍数都不会超过这个最大值。然后从1到max_num遍历每个数字x
    • 如果x在数组中存在,就遍历它的所有倍数(2x、3x...直到超过max_num),只要某个倍数y在数组中存在,就标记y为「符合条件」(因为y能被x整除,且x≠y,满足“被至少一个其他元素整除”)。
    • 如果x在数组中出现多次(比如[2,2]),那x自己也符合条件,因为有其他相同的元素可以整除它。
  3. 统计结果:最后遍历原数组,数一下所有被标记为符合条件的元素总数。

示例演示(以数组[1,2,3,4]为例)

  • 频率数组:freq[1]=1freq[2]=1freq[3]=1freq[4]=1,最大值max_num=4
  • 遍历x=1:它的倍数是2、3、4,这些都在数组里,所以标记2、3、4为符合条件。
  • 遍历x=2:倍数是4,已经被标记过,无需重复操作。
  • 遍历x=3:倍数是6,超过最大值,直接跳过。
  • 遍历x=4:倍数是8,超过最大值,直接跳过。
  • 最终符合条件的元素是2、3、4,总数为3,和示例结果一致。

代码实现(Python)

def count_divisible_elements(arr):
    if not arr:
        return 0
    
    # 单独处理数组中的0元素
    zero_count = arr.count(0)
    non_zero_arr = [num for num in arr if num != 0]
    
    # 全是0的情况:每个0都能被其他0整除
    if not non_zero_arr:
        return len(arr)
    
    max_num = max(non_zero_arr)
    # 初始化频率数组
    freq = [0] * (max_num + 1)
    for num in non_zero_arr:
        freq[num] += 1
    
    # 标记符合条件的非0元素
    is_divisible = [False] * (max_num + 1)
    for x in range(1, max_num + 1):
        if freq[x] == 0:
            continue
        # 遍历x的所有倍数
        multiple = 2 * x
        while multiple <= max_num:
            if freq[multiple] > 0:
                is_divisible[multiple] = True
            multiple += x
        # 同一元素出现多次的情况
        if freq[x] > 1:
            is_divisible[x] = True
    
    # 统计非0元素中符合条件的数量
    non_zero_count = 0
    for num in non_zero_arr:
        if is_divisible[num]:
            non_zero_count += 1
    
    # 所有0都符合条件(因为存在非0元素可以整除它)
    return non_zero_count + zero_count

# 测试用例
print(count_divisible_elements([1,2,3,4]))    # 输出3
print(count_divisible_elements([2,2,4]))       # 输出3
print(count_divisible_elements([0,1,2]))       # 输出1
print(count_divisible_elements([0,0,0]))        # 输出3

时间复杂度分析

假设数组中的最大值为M,遍历每个数字的倍数的总次数是M/1 + M/2 + M/3 + ... + M/M,这个和的近似值是M log M,比暴力法的O(n²)高效得多。尤其是当数组元素数量n很大但M不大时,这个优势会非常明显。

注意点

  • 重复元素:比如数组[2,2],两个元素都能被彼此整除,所以结果是2,代码里通过判断freq[x]>1来处理这种情况。
  • 0元素:0能被任何非0元素整除,但0不能整除任何数。如果数组里有0且存在非0元素,所有0都符合条件;如果全是0,所有元素都符合条件。

内容的提问来源于stack exchange,提问作者Sanjay M

火山引擎 最新活动