zoukankan      html  css  js  c++  java
  • Leetcode: 327. Count of Range Sum

    Descrption

    Given an integer array nums, return the number of range sums that lie in [lower, upper] inclusive.
    Range sum S(i, j) is defined as the sum of the elements in nums between indices i and j (i ≤ j), inclusive.
    

    Note

    A naive algorithm of O(n2) is trivial. You MUST do better than that.
    

    Example

    Input: nums = [-2,5,-1], lower = -2, upper = 2,
    Output: 3
    Explanation: The three ranges are : [0,0], [2,2], [0,2] and their respective sums are: -2, -1, 2.
    

    分析

    最初的思路

    1. 计算前缀和并用 bisect 加入到数组 presum[]
    2. 使用 presum[] 计算 lower, upper 中的个数 。 此时计算的所有数据均是以 nums[0] 开头的数据。
        从 presum 中删除 nums[0] 数据, 并调整 lower 和 upper 的值 (这样 presum[] 数组中的数字就变相是 nums[1] 开头的前缀和)
    3. 返回步骤 2 
    
    结果是: 最初的版本超时,后续的版本做了一点点的优化。结果是只速度上只超过 8% 的提交
    

    改进的思路

    首先,个人认为最初的版本的代码的 时间复杂度是 nlogn。 不应该有这么差的表现。 一定有可以优化的地方,当时猜测 瓶颈是  从 presum[] 中删除 nums[i] 的这步操作。 
    1. 先计算 nums 的总和, 并存储到 ssum
    2. 从后往前迭代数据 , 即 range(N-1, -1, -1)。 根据 ssum 和 nums[i] 调整 lower 和 hi 的值。
        使用 bisect 搜索满足条件的个数。 将 nums[i] 加入到 presum[]
    3. 返回步骤2
    
    结果: 战胜 100 % 的提交
    

    code

    • TLE
    class Solution(object):
        def _do(self, nums, lower, hi):
            h, h2 = [] , []
            ans, ssum, N =0,  0, len(nums)
            for i, v in enumerate(nums):
                ssum += v
                bisect.insort(h2, ssum)
                bisect.insort(h, (ssum, i))
            # print(h)
            # print(h2)
            ssum = 0
            for i in range(N):
                hp = bisect.bisect_right(h2, hi)
                lw = bisect.bisect_left(h2, lower)
                # print(hp, lw, h, lower, hi)
                ssum += nums[i]
                # do sth
                hi += nums[i]
                lower += nums[i]
                ans += hp-lw
                ep1 = bisect.bisect_right(h, (ssum,i))
                if ep1 == len(h):
                    ep1 -= 1
                while True:
                    if h[ep1][1] == i:
                        h2 = h2[:ep1] + h2[ep1+1:]
                        h = h[:ep1] + h[ep1+1:]
                        break
                    ep1 -= 1
            return ans
    
    • beat 8%
    去除了 h2 的操作, 少一个数组需要维护
    class Solution(object):
        def _do(self, nums, lower, hi):
    
            ans, ssum, N, h =0,  0, len(nums), []
    
            for i, v in enumerate(nums):
                ssum += v
                bisect.insort(h, ssum)
    
            # print(h)
            # print(h2)
            ssum = 0
            for i in range(N):
                hp = bisect.bisect_right(h, hi)
                lw = bisect.bisect_left(h, lower)
                # print(hp, lw, h, lower, hi)
                ssum += nums[i]
                # do sth
                hi += nums[i]
                lower += nums[i]
                ans += hp-lw
                ep1 = bisect.bisect_right(h, ssum)
                if ep1 == len(h):
                    ep1 -= 1
                while True:
                    if h[ep1] == ssum:
                        h = h[:ep1] + h[ep1+1:]
                        break
                    ep1 -= 1
            return ans
    
    
    • beat 100 %
    class Solution(object):
        def _do(self, nums, lower, hi):
            ans, ssum, N, =0,  sum(nums), len(nums)
            h = [ssum]
            
            for i in range(N-1, -1, -1):
                ssum -= nums[i]
                
                temp_lower, temp_upper = lower + ssum, hi + ssum
                ans += bisect.bisect_right(h, temp_upper) -  bisect.bisect_left(h, temp_lower)
                
                bisect.insort(h, ssum)
            return ans
    
    

    总结

    • 二分思想玩的不错~
  • 相关阅读:
    自定义Python枚举
    解决Django跨域访问的问题
    BBS项目细节总结
    面向对象进阶
    面向对象
    三级菜单
    常用模块
    内置函数与匿名函数及递归
    迭代器和生成器
    函数
  • 原文地址:https://www.cnblogs.com/tmortred/p/13362807.html
Copyright © 2011-2022 走看看