区间计算的数据结构

前言:

前缀和:区间查询O(1),修改O(N);
线段树:区间查询O(lgN),修改O(lgN);
差分数组:区间修改O(1),但是在查询数组中某个位置的数时,就要根据差分数组从前往后递推求值。

一、线段树

自上而下递归的思想。

/**
 * 线段树
 */
public class SegementTreePractice2 {
    private static Segement root;
    class Segement {
        // 线段表示的区间[L,R]
        int L, R;
        // [L, R]内的有效长度value
        int value;
        Segement left, right;
        public Segement(int L, int R, int value) {
            this.L = L;
            this.R = R;
            this.value = value;
        }
    }
    /**
     * 构建线段树
     */
    private Segement buildTree(int[] arr, int left, int right) {
        if (left == right) {
            return new Segement(left, right, arr[left]);
        }
        int mid = (left + right) / 2;
        Segement leftNode = buildTree(arr, left, mid);
        Segement rightNode = buildTree(arr, mid + 1, right);
        Segement node = new Segement(left, right, leftNode.value + rightNode.value);
        node.left = leftNode;
        node.right = rightNode;
        return node;
    }
		/**
     * 根据线段树求 arr[left, right]的大小
     */
    private int query(int left, int right, Segement root) {
        if (left == root.L && right == root.R) {
            return root.value;
        }
        // rightNode区间能覆盖[left, right]
        if (root.right.L <= left && root.right.R >= right) {
            return query(left, right, root.right);
        }
        // leftNode区间能覆盖[left, right]
        if (root.left.L <= left && root.left.R >= right) {
            return query(left, right, root.left);
        }

        int mid = (root.L + root.R) / 2;
        int leftQuery = query(left, mid, root.left);
        int rightQuery = query(mid + 1, right, root.right);
        return leftQuery + rightQuery;
    }

    /**
     * arr[index]修改为value,更新线段树
     */
    private void update(int index, int value, Segement root) {
        if (root.L == root.R) {
            if (root.L == index) {
                root.value = value;
            }
            return;
        }
        // index在左区间还是右区间
        if (root.left.L <= index && root.left.R >= index) {
            update(index, value, root.left);
        } else {
            update(index, value, root.right);
        }
        root.value = root.left.value + root.right.value;
    }
}

二、差分数组

diff[i]数组的意义:nums[i]与nums[i-1]的差。所以要查询数组中某个位置的数时,就要根据差分数组从头往后递推求值。

int[] getDiff(int[] nums){
	int n = nums.length;
	int[] diff = new int[n + 1];
	diff[0] = nums[0];
	for (int i = 1; i < n; i++) {
		diff[i] = nums[i] - nums[i - 1];
	}
}
如果想对[i, j]区间加a,那就diff[i]+a, diff[j+1]-a;
如果想对[i, j]区间减a,那就diff[i]-a, diff[j+1]+a。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值