LeetCode 327. 区间和的个数

题目链接:https://leetcode-cn.com/problems/count-of-range-sum/

在这里插入图片描述
题意:给定一个数组nums,找出子数组中元素和在[lower, upper]中有多少个,
[-2, 5, -1]的子数组有[-2, 5, -1],[-2, 5],[-2],[5, -1],[5],[-1]共6个,满足条件的共3个

思路:
1.维护一个平衡二叉树,将所有以下标以0为起点的子数组和插入二叉树中
([-2, 5, -1] = 2,[-2, 5] = 3,[-2] = -2)
满足在[-2, 2]区间内的有2个
2.以下标1为起点的子数组[5, -1], [5]在区间[-2, 2]等价于[-2, 5, -1],[-2, 5]在区间[-4, 0]

class Program_327 {
    class SplayTree {
        public SplayNode Root;
        public class SplayNode {
            //结点为根的子树中总共有多少个结点
            public int Size;
            //当前结点有多少个Value
            public int Count;
            //当前结点的值
            public long Value;
            //父结点
            public SplayNode Pre;
            //左右子结点
            public SplayNode[] Childs = new SplayNode[2];
            public SplayNode(long _value, SplayNode _pre, SplayNode left = null, SplayNode right = null) {
                Size = 1;
                Count = 1;
                Value = _value;
                Pre = _pre;
                Childs[0] = left;
                Childs[1] = right;
            }
        }
        public SplayTree() {
            //创建两个边界结点
            Root = new SplayNode(long.MinValue, null);
            Root.Childs[1] = new SplayNode(long.MaxValue, Root);
            PushUp(Root);
        }

        /// <summary>
        /// 返回子节点方向
        /// </summary>
        /// <param name="rw"></param>
        /// <returns>rw是父结点的左儿子返回0,右儿子返回1</returns>
        public int F(SplayNode rw) {
            if (rw.Pre.Childs[0] == rw) {
                return 0;
            }
            return 1;
        }

        /// <summary>
        /// 向上更新状态
        /// </summary>
        public void PushUp(SplayNode rt) {
            rt.Size = rt.Count;
            for (int i = 0; i < 2; i++) {
                if (null != rt.Childs[i]) {
                    rt.Childs[i].Pre = rt;
                    rt.Size += rt.Childs[i].Size;
                }
            }
        }

        //将rw旋转到父结点的位置
        public void Rotate(SplayNode rw) {
            int chd = F(rw);
            SplayNode preNode = rw.Pre;

            rw.Pre = preNode.Pre;
            if (null != preNode.Pre) {
                preNode.Pre.Childs[F(preNode)] = rw;
            }
            preNode.Childs[chd] = rw.Childs[1 - chd];
            rw.Childs[1 - chd] = preNode;

            PushUp(preNode);
            PushUp(rw);
        }


        /// <summary>
        /// 调整SplayTree, 将rw调整到rt的子结点
        /// </summary>
        /// <returns></returns>
        public SplayNode Splay(SplayNode rt, SplayNode rw) {
            while (rw.Pre != rt) {
                SplayNode preNode = rw.Pre;
                if (rt == preNode.Pre || F(rw) != F(preNode)) {
                    Rotate(rw);
                } else {
                    Rotate(preNode);
                    Rotate(rw);
                }
            }
            if (null != rt) {
                PushUp(rt);
            } else {
                Root = rw;
            }
            return rw;
        }

        /// <summary>
        /// 插入结点
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public SplayNode Insert(long value) {
            SplayNode curNode = Root;
            SplayNode newNode = new SplayNode(value, null);
            while (true) {
                curNode.Size++;
                int nextChd = 0;
                if (value == curNode.Value) {
                    newNode = curNode;
                    newNode.Count++;
                    break;
                } else if (value < curNode.Value) {
                    nextChd = 0;
                } else {
                    nextChd = 1;
                }
                if (null == curNode.Childs[nextChd]) {
                    newNode.Pre = curNode;
                    curNode.Childs[nextChd] = newNode;
                    break;
                }
                curNode = curNode.Childs[nextChd];
            }
            return newNode;
        }


        /// <summary>
        /// 删除结点
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool Delete(long value) {
            SplayNode node = FindRange(value, value);
            if (null == node) {
                return false;
            }
            node.Count--;
            node.Size--;
            if (node.Count <= 0) {
                //删除结点
                node.Pre.Childs[F(node)] = null;
            }
            //减小size
            SplayNode curNode = node;
            while (null != curNode.Pre) {
                curNode = curNode.Pre;
                PushUp(curNode);
            }
            return true;
        }

        /// <summary>
        /// 返回小于value的最大的Node
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public SplayNode FindNode1(long value) {
            SplayNode retNode = null;
            SplayNode curNode = Root;
            while (null != curNode) {
                if (value <= curNode.Value) {
                    curNode = curNode.Childs[0];
                }else {
                    if (null != curNode && (null == retNode || retNode.Value < curNode.Value)) {
                        retNode = curNode;
                    }
                    curNode = curNode.Childs[1];
                }
            }
            return retNode;
        }

        /// <summary>
        /// 返回大于value的最小的Node
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public SplayNode FindNode2(long value) {
            SplayNode retNode = null;
            SplayNode curNode = Root;
            while (null != curNode) {
                if (value < curNode.Value) {
                    if (null != curNode && (null == retNode || curNode.Value < retNode.Value)) {
                        retNode = curNode;
                    }
                    curNode = curNode.Childs[0];
                } else {
                    curNode = curNode.Childs[1];
                }
            }
            return retNode;
        }


        /// <summary>
        /// 将区间内所有结点放到一个子树上,并返回子树根结点
        /// </summary>
        /// <param name="min"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        public SplayNode FindRange(long min, long max) {
            SplayNode minNode = FindNode1(min);
            SplayNode maxNode = FindNode2(max);
            //minNode旋转到Root
            Splay(null, minNode);
            //maxNode旋转为Root右子结点
            Splay(minNode, maxNode);
            return maxNode.Childs[0];
        }
    }

    public int CountRangeSum(int[] nums, int lower, int upper) {
        //前缀和
        long[] Sum = new long[10005];
        //伸展树
        SplayTree splay = new SplayTree();
        Sum[0] = 0;
        for (int i = 1; i <= nums.Length; i++) {
            Sum[i] = Sum[i - 1] + nums[i - 1];
            splay.Splay(null, splay.Insert(Sum[i]));
        }
        int result = 0;
        long tempLower = lower;
        long tempUpper = upper;
        for (int i = 0; i < nums.Length; i++) {
            if (0 < i) {
                splay.Delete(Sum[i]);
            }
            SplayTree.SplayNode node = splay.FindRange(tempLower, tempUpper);
            if (null != node) {
                result += node.Size;
            }
            tempLower += nums[i];
            tempUpper += nums[i];
        }
        return result;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

achonor

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值