307RangeSumQueryMutable

题意:给定一个整数数组nums,找到数组小标为i,j(i小于j且包含)之间的元素的和,同时update(i,val)函数将下标为i的元素的值该为val

声明:1数组的值只能被update函数修改;2 update和sumRange函数调用分布均匀。

思路:使用数据结构segment tree, 节点保存区间、区间的和,以及覆盖标志,更新操作O(logn),求和O(logn)

注意问题: int nums[] = new int[0] 此时数组nums不为null且长度为0;而int nums[] 只声明引用类型的变量,则nums为null。必须判断nums.length == 0,具体解释参考链接http://coolshell.cn/articles/11377.html

public class NumArray {
    Node root;
	int[] nums;
	
	static class Node{
		int sum;
		int leftIndex;
		int rightIndex;
		Node leftChild; //null
		Node rightChild; //null
		
		public Node(int left, int right) {
			super();
			this.leftIndex = left;
			this.rightIndex = right;
			sum = 0;
		}
	}
    public NumArray(int[] nums) {
        this.nums = nums;
        if(nums == null || nums.length == 0)
            return;
		root = buildSegmentTree(0, nums.length-1, nums);
    }
    
    private static Node buildSegmentTree(int left, int right, int[] nums) {
		Node node = new Node(left, right);
		if(right - left == 0){
			node.sum = nums[left]; //leaf node composed of length 1
			node.leftChild = null;
			node.rightChild = null;
		}else{
			int mid = (left + right)/2;
			node.leftChild = buildSegmentTree(left, mid, nums); //intermediate node
			node.rightChild = buildSegmentTree(mid+1, right, nums); //non-interactive
			node.sum = node.leftChild.sum + node.rightChild.sum;
		}	
		return node;
	}

    void update(int i, int val) {
        assert(i >= 0 && i < nums.length);
		int delta = val - nums[i];
		nums[i] = val;
		update(root, i, delta);
    }
    
    private void update(Node root, int i, int delta) {
		root.sum += delta;
		if(root.rightIndex - root.leftIndex == 0)
			return;
		int mid = (root.rightIndex + root.leftIndex)/2;
		if(i <= mid){
			update(root.leftChild, i, delta);
		} else{
			update(root.rightChild, i, delta);
		}
	}
    

    public int sumRange(int i, int j) {
         int sum = 0;
		 if(i == j) return nums[i];
		 sum += sumRange(root, i, j);
		 return sum;
    }
    
    private int sumRange(Node root, int i, int j) {//time:O(logn)
		if(i == root.leftIndex && j == root.rightIndex){
			return root.sum;
		}
		int mid = (root.rightIndex + root.leftIndex)/2;
		if(i > mid){
			return sumRange(root.rightChild, i, j);
		}
		if(j < mid+1)
			return sumRange(root.leftChild, i, j);
		else{
			return sumRange(root.leftChild, i, mid) + sumRange(root.rightChild, mid+1, j);
		}
	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值