erlang算法系列-线段树-315. 计算右侧小于当前元素的个数(困难)

线段树解法,线段树结构:{Min, Max, Value, Small, Big} = TreeData。
Min数据段最小值,Max数据段最大值,Value数据段数据个数,Small左子树,Big右子树。
左右子树的划分值Mid = Min + (Max-Min) div 2, Small为{Min,Mid},Big为{Mid+1,Max}。

每插入一个数Num的时候,更新所有Num属于{Min,Max}的节点的Value+1,时间复杂度O(lgN)。同样计算所有{Min,Num-1}的个数,遍历线段树的时间复杂度也在O(lgN)。

计算右侧小于当前元素的个数-原题

给你一个整数数组 nums ,按要求返回一个新数组 counts 。数组 counts 有该性质: counts[i] 的值是  nums[i] 右侧小于 nums[i] 的元素的数量。

示例 1:

输入:nums = [5,2,6,1]
输出:[2,1,1,0] 
解释:
5 的右侧有 2 个更小的元素 (2 和 1)
2 的右侧仅有 1 个更小的元素 (1)
6 的右侧有 1 个更小的元素 (1)
1 的右侧有 0 个更小的元素
示例 2:

输入:nums = [-1]
输出:[0]
示例 3:

输入:nums = [-1,-1]
输出:[0,0]

提示:

1 <= nums.length <= 10^5
-10^4 <= nums[i] <= 10^4

-spec count_smaller(Nums :: [integer()]) -> [integer()].
count_smaller(Nums) ->
    Min = lists:min(Nums),
    Max = lists:max(Nums),
    TreeData = {Min, Max, 0, nil, nil},    
    do_count(lists:reverse(Nums), Min, Max, TreeData, []).

do_count([],  Min, Max, Tree, Ans) ->
    Ans;
do_count([N | Nums],  Min, Max, Tree, Ans) ->
    NewTree = insert_to_tree(Min, Max, N, Tree),
    Count = get_small_num(Min, Max, N, Tree),
    do_count(Nums,  Min, Max, NewTree, [Count | Ans]).  

insert_to_tree(Min, Min, N, TreeData) ->
    case TreeData of
        {Min, Min, Value, nil, nil} ->
            {Min, Min, Value + 1, nil, nil};
        _ ->
            {Min, Min, 1, nil, nil}
    end;
insert_to_tree(Min, Max, N, TreeData) ->     
    if
        TreeData =:= nil ->
            Value = 0, Small = nil, Big = nil;
        true ->
            {Min, Max, Value, Small, Big} = TreeData
    end,    
    Mid = Min + (Max-Min) div 2,

    if
        Mid >= N ->
            {Min, Max, Value + 1, insert_to_tree(Min, Mid, N, Small), Big};
        true ->
            {Min, Max, Value + 1, Small, insert_to_tree(Mid + 1, Max, N, Big)}
    end. 

get_small_num(Min, Min, N, TreeData) ->
    case TreeData of
        {Min, Min, Value, nil, nil} ->
            if  
                N > Min ->
                    Value;
                true ->
                    0
            end;
        _ ->
            0
    end;
get_small_num(Min, Max, N, TreeData) ->     
    if
        TreeData =:= nil ->
            0;
        true ->
            {Min, Max, Value, Small, Big} = TreeData,
            if
                N > Max ->
                    Value;
                Min > N ->
                    0;
                true  ->
                    Mid = Min + (Max-Min) div 2,
                    if
                        Mid >= N ->
                            get_small_num(Min, Mid, N, Small);
                        true ->
                            get_small_num(Min, Mid, N, Small) + get_small_num(Mid + 1, Max, N, Big)
                    end
            end
    end.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值