20、SQRT 分解

内容来自刘宇波老师算法与数据结构体系课

1、SQRT 分解介绍

image

2、区间查询图示

image

3、单元素更新图示

image

4、SQRT 分解实现

307 - 区域和检索 - 数组可修改

/**
 * 通过 SQRT 分解解决
 */
@SuppressWarnings("all")
public class NumArray {

    private int[] data;
    private int[] blocks;
    private int N;  // 元素总数
    private int B;  // 每组元素个数
    private int Bn; // 组数

    public NumArray(int[] nums) {
        N = nums.length;
        if (N == 0) return;

        B = (int) Math.sqrt(N);
        Bn = N / B + (N % B != 0 ? 1 : 0);

        data = Arrays.copyOf(nums, N);
        blocks = new int[Bn];
        for (int i = 0; i < N; i++) blocks[i / B] += data[i];
    }

    public void update(int index, int val) {
        if (index < 0 || index >= N) return;
        int diff = val - data[index];
        data[index] = val;
        blocks[index / B] += diff;
    }

    public int sumRange(int l, int r) {
        if (l < 0 || l >= N || r < 0 || r >= N || l > r) return 0;

        int sum = 0;
        int bStart = l / B;
        int bEnd = r / B;

        if (Math.abs(bStart - bEnd) <= 1) {
            for (int i = l; i <= r; i++) sum += data[i];
        } else {
            for (int i = l; i < (bStart + 1) * B; i++) sum += data[i]; // bStart 组
            for (int i = bStart + 1; i < bEnd; i++) sum += blocks[i];  // [bStart + 1 ... bEnd - 1] 组
            for (int i = bEnd * B; i <= r; i++) sum += data[i];        // bEnd 组
        }

        return sum;
    }
}

5、通用 SQRT 分解

public interface Merger<E> {

    E merge(E a, E b);

}
/**
 * 通用 SQRT 分解
 * 注意 merge 的元素可能为 null
 * 注意并不是每一组的元素个数都为 B(更新操作)
 * N / B, 第几组
 * N % B, 第几组的第几个
 */
public class SQRTDecomposition<E> {

    private E[] data;
    private E[] blocks;
    private int N;  // 元素总数
    private int B;  // 每组元素个数
    private int Bn; // 组数
    private Merger<E> merger;

    public SQRTDecomposition(E[] arr, Merger<E> merger) {
        if (arr.length == 0) return;
        this.merger = merger;

        N = arr.length;
        B = (int) Math.sqrt(N);
        Bn = N / B + (N % B != 0 ? 1 : 0);

        data = Arrays.copyOf(arr, N);
        blocks = (E[]) new Object[Bn];
        buildBlocks();
    }

    private void buildBlocks() {
        for (int i = 0; i < N; i++) {
            if (i % B == 0) blocks[i / B] = data[i];
            else blocks[i / B] = merger.merge(blocks[i / B], data[i]);
        }
    }

    public void update(int index, E val) {
        if (index < 0 || index >= N) return;
        data[index] = val;
        
        int b = index / B;
        blocks[b] = data[b * B];
        for (int i = b * B + 1; i < Math.min((b + 1) * B, N); i++) blocks[b] = merger.merge(blocks[b], data[i]);
    }

    public E query(int l, int r) {
        if (l < 0 || l >= N || r < 0 || r >= N || l > r) return null;

        int bStart = l / B;
        int bEnd = r / B;

        E res = data[l];
        if (Math.abs(bStart - bEnd) <= 1) {
            for (int i = l + 1; i <= r; i++) res = merger.merge(res, data[i]);
        } else {
            for (int i = l + 1; i < (bStart + 1) * B; i++) res = merger.merge(res, data[i]); // bStart 组
            for (int i = bStart + 1; i < bEnd; i++) res = merger.merge(res, blocks[i]);      // [bStart + 1 ... bEnd - 1] 组
            for (int i = bEnd * B; i <= r; i++) res = merger.merge(res, data[i]);            // bEnd 组
        }

        return res;
    }
}
Integer[] nums = {-2, 0, 3, -5, 2, -1};
SQRTDecomposition<Integer> sumSQRT = new SQRTDecomposition<>(nums, Integer::sum);
SQRTDecomposition<Integer> maxSQRT = new SQRTDecomposition<>(nums, Math::max);
SQRTDecomposition<Integer> minSQRT = new SQRTDecomposition<>(nums, Math::min);
posted @ 2023-04-13 16:16  lidongdongdong~  阅读(17)  评论(0编辑  收藏  举报