线段树

 地址

方法一

"""
    The idea here is to build a segment tree. Each node stores the left and right
    endpoint of an interval and the sum of that interval. All of the leaves will store
    elements of the array and each internal node will store sum of leaves under it.
    Creating the tree takes O(n) time. Query and updates are both O(log n).
"""

#Segment tree node
class Node(object):
    def __init__(self, start, end):
        self.start = start
        self.end = end
        self.total = 0
        self.left = None
        self.right = None
        

class NumArray(object):
    def __init__(self, nums):
        """
        initialize your data structure here.
        :type nums: List[int]
        """
        #helper function to create the tree from input array
        def createTree(nums, l, r):
            
            #base case
            if l > r:
                return None
                
            #leaf node
            if l == r:
                n = Node(l, r)
                n.total = nums[l]
                return n
            
            mid = (l + r) // 2
            
            root = Node(l, r)
            
            #recursively build the Segment tree
            root.left = createTree(nums, l, mid)
            root.right = createTree(nums, mid+1, r)
            
            #Total stores the sum of all leaves under root
            #i.e. those elements lying between (start, end)
            root.total = root.left.total + root.right.total
                
            return root
        
        self.root = createTree(nums, 0, len(nums)-1)
            
    def update(self, i, val):
        """
        :type i: int
        :type val: int
        :rtype: int
        """
        #Helper function to update a value
        def updateVal(root, i, val):
            
            #Base case. The actual value will be updated in a leaf.
            #The total is then propogated upwards
            if root.start == root.end:
                root.total = val
                return val
        
            mid = (root.start + root.end) // 2
            
            #If the index is less than the mid, that leaf must be in the left subtree
            if i <= mid:
                updateVal(root.left, i, val)
                
            #Otherwise, the right subtree
            else:
                updateVal(root.right, i, val)
            
            #Propogate the changes after recursive call returns
            root.total = root.left.total + root.right.total
            
            return root.total
        
        return updateVal(self.root, i, val)

    def sumRange(self, i, j):
        """
        sum of elements nums[i..j], inclusive.
        :type i: int
        :type j: int
        :rtype: int
        """
        #Helper function to calculate range sum
        def rangeSum(root, i, j):
            
            #If the range exactly matches the root, we already have the sum
            if root.start == i and root.end == j:
                return root.total
            
            mid = (root.start + root.end) // 2
            
            #If end of the range is less than the mid, the entire interval lies
            #in the left subtree
            if j <= mid:
                return rangeSum(root.left, i, j)
            
            #If start of the interval is greater than mid, the entire inteval lies
            #in the right subtree
            elif i >= mid + 1:
                return rangeSum(root.right, i, j)
            
            #Otherwise, the interval is split. So we calculate the sum recursively,
            #by splitting the interval
            else:
                return rangeSum(root.left, i, mid) + rangeSum(root.right, mid+1, j)
        
        return rangeSum(self.root, i, j)
                


# Your NumArray object will be instantiated and called as such:
# numArray = NumArray(nums)
# numArray.sumRange(0, 1)
# numArray.update(1, 10)
# numArray.sumRange(1, 2)

 

方法二 

class NumArray(object):

	def __init__(self, nums):
		self.l = len(nums)
		self.tree = [0]*self.l + nums
		for i in range(self.l - 1, 0, -1):
			self.tree[i] = self.tree[i<<1] + self.tree[i<<1|1]
	
	def update(self, i, val):
		n = self.l + i
		self.tree[n] = val
		while n > 1:
			self.tree[n>>1] = self.tree[n] + self.tree[n^1]
			n >>= 1
		
	
	def sumRange(self, i, j):
		m = self.l + i
		n = self.l + j
		res = 0
		while m <= n:
			if m & 1:
				res += self.tree[m]
				m += 1
			m >>= 1
			if n & 1 ==0:
				res += self.tree[n]
				n -= 1
			n >>= 1
		return res

 

方法三(与方法一相似,存储方式不同)

#define LOWER_BOUND(S,PRESUM) (lower_bound(S.begin(),S.end(),(PRESUM)) - S.begin() + 1)
#define UPPER_BOUND(S,PRESUM) (upper_bound(S.begin(),S.end(),(PRESUM)) - S.begin())
class Solution {
public:
    int countRangeSum(vector& nums, int lower, int upper) {

        int n= nums.size();
        int ret = 0;
        vector S(n+1,0);
        for(int i=1;i<=n;i++)S[i] = S[i-1] + nums[i-1];
        
        sort(S.begin(),S.end());
        S.erase(unique(S.begin(),S.end()),S.end());

        int len = S.size();
        value = vector(4*(len+1),0);
        int64_t presum = 0;
        add(LOWER_BOUND(S,presum),1,1,len);
        for(int i=0;i             presum += nums[i];
            int64_t up = LOWER_BOUND(S,presum - upper);
            int64_t low = UPPER_BOUND(S,presum - lower);
            if(up <= low)
            ret +=  query(up,low,1,1,len) ;
            add(LOWER_BOUND(S,presum),1,1,len);
            
        }
        
        return ret;
    }        
    
private:
    vector value;
    void add(int v,int o,int L,int R){
        if(L == R)value[o]++;
        else{
            int M = L + (R-L)/2;
            if(v <= M) add(v,o*2,L,M);
            else add(v,o*2+1,M+1,R);
            value[o] = value[2*o] + value[2*o + 1];
        }
    }
    int query(int ql,int qr,int o,int L,int R){
        if(ql <= L && R <= qr) return value[o];
        int ans = 0;
        int M = L + (R-L)/2;
        if(ql <= M) ans += query(ql,qr,2*o,L,M);
        if(M < qr) ans += query(ql,qr,2*o+1,M+1,R);
        return ans;
    }
    
        
};

线段树理论上需要2*n大小的数组,但是实际为了防止溢出,需要 4*n的大小

作者:xu-yuan-shu
链接:https://leetcode-cn.com/problems/count-of-range-sum/solution/327qu-jian-he-de-ge-shu-ti-jie-zong-he-by-xu-yuan-/
 

你可能感兴趣的:(数据结构)