erlang算法系列-leetclode-2183. 统计可以被 K 整除的下标对数目(困难)

2183. 统计可以被 K 整除的下标对数目-原题

给你一个下标从 0 开始、长度为 n 的整数数组 nums 和一个整数 k ,返回满足下述条件的下标对 (i, j) 的数目:

0 <= i < j <= n - 1 且
nums[i] * nums[j] 能被 k 整除。

示例 1:

输入:nums = [1,2,3,4,5], k = 2
输出:7
解释:
共有 7 对下标的对应积可以被 2 整除:
(0, 1)、(0, 3)、(1, 2)、(1, 3)、(1, 4)、(2, 3) 和 (3, 4)
它们的积分别是 2、4、6、8、10、12 和 20 。
其他下标对,例如 (0, 2) 和 (2, 4) 的乘积分别是 3 和 15 ,都无法被 2 整除。    
示例 2:

输入:nums = [1,2,3,4], k = 5
输出:0
解释:不存在对应积可以被 5 整除的下标对。

提示:

1 <= nums.length <= 10^5
1 <= nums[i], k <= 10^5

解题思路

最大公倍数+统计,最要是计算K/GCD(Ni,K) 在数组中出现的次数。

-spec count_pairs(Nums :: [integer()], K :: integer()) -> integer().
count_pairs(Nums, K) ->
    
    Map = maps:new(),
    Map1 = init_map(Nums, Map),
    Max = lists:max(Nums),
    Map2 = count_map(1, Max, Map1),
    do_count(Nums, K, Map2, 0).

do_count([], K, Map, Ans) ->
    Ans div 2;
do_count([N | Nums], K, Map, Ans) ->
    M = K div gcd(N, K),
    Ans1 = Ans + maps:get(M, Map, 0),
    if
        (N * N) rem K =:= 0 ->
            do_count(Nums, K, Map, Ans1 -1);
        true ->
            do_count(Nums, K, Map, Ans1)
    end.

init_map([], Map) ->
    Map;
init_map([N | Nums], Map) ->
    Map1 = add_to_map(N, Map, 1),
    init_map(Nums, Map1).

count_map(I, Max, Map) when I > Max->
    Map;
count_map(I, Max, Map) ->
    NewMap = count_map1(I*2, Max, I, Map),
    count_map(I + 1, Max, NewMap).

count_map1(J, Max, I, Map) when J > Max ->
    Map;
count_map1(J, Max, I, Map) ->
    Value = maps:get(J, Map, 0),
    if
        Value =/= 0 ->
            NewMap = add_to_map(I, Map, Value),
            count_map1(J + I, Max, I, NewMap);
        true ->
            count_map1(J + I, Max, I, Map)
    end.

add_to_map(Key, Map, Num) ->
    case maps:find(Key, Map) of
        {ok, Value} ->
            maps:update(Key, Value + Num, Map);
        _ ->
            maps:put(Key, Num, Map)
    end.

gcd(0, Max) ->
    Max;
gcd(Min, Max) ->
    if  
        Min > Max ->
            gcd(Min rem Max, Max);
        true ->
            gcd(Max rem Min, Min)
    end.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值