📌  相关文章
📜  在给定的整数序列中查找 L 到 R 范围内的总和(1)

📅  最后修改于: 2023-12-03 15:23:37.200000             🧑  作者: Mango

在给定的整数序列中查找 L 到 R 范围内的总和

这是一个常见的问题,通常需要通过编写算法实现。以下是一些常见的算法实现,可以供程序员进行参考。

算法一

遍历给定的整数序列,将其中属于 L 到 R 范围内的元素加起来,得到总和。

def sum_between_l_and_r(arr, L, R):
    result = 0
    for num in arr:
        if L <= num <= R:
            result += num
    return result
public static int sumBetweenLAndR(int[] arr, int L, int R) {
    int result = 0;
    for (int num : arr) {
        if (num >= L && num <= R) {
            result += num;
        }
    }
    return result;
}

时间复杂度为 O(n),其中 n 为给定的整数序列的长度。

算法二

使用前缀和优化算法一,将序列的所有前缀和计算出来,对于每一个查询,只需要使用两个前缀和相减得到 L 到 R 范围内的总和。

def sum_between_l_and_r(arr, L, R):
    n = len(arr)
    prefix_sum = [0] * (n + 1)
    for i in range(1, n + 1):
        prefix_sum[i] = prefix_sum[i - 1] + arr[i - 1]
    return prefix_sum[R + 1] - prefix_sum[L]
public static int sumBetweenLAndR(int[] arr, int L, int R) {
    int n = arr.length;
    int[] prefixSum = new int[n + 1];
    for (int i = 1; i <= n; i++) {
        prefixSum[i] = prefixSum[i - 1] + arr[i - 1];
    }
    return prefixSum[R + 1] - prefixSum[L];
}

时间复杂度为 O(n),其中 n 为给定的整数序列的长度。预处理的时间复杂度为 O(n),每次查询的时间复杂度为 O(1)。

算法三

使用线段树维护序列区间和,可以进行单点修改和区间查询。

class SegmentTree:
    def __init__(self, arr):
        n = len(arr)
        self.tree = [0] * (4 * n)
        self.build(arr, 1, 0, n - 1)

    def build(self, arr, curNode, left, right):
        if left == right:
            self.tree[curNode] = arr[left]
        else:
            mid = (left + right) // 2
            self.build(arr, 2 * curNode, left, mid)
            self.build(arr, 2 * curNode + 1, mid + 1, right)
            self.tree[curNode] = self.tree[2 * curNode] + self.tree[2 * curNode + 1]

    def update(self, curNode, left, right, idx, val):
        if left == right:
            self.tree[curNode] = val
        else:
            mid = (left + right) // 2
            if idx <= mid:
                self.update(2 * curNode, left, mid, idx, val)
            else:
                self.update(2 * curNode + 1, mid + 1, right, idx, val)
            self.tree[curNode] = self.tree[2 * curNode] + self.tree[2 * curNode + 1]

    def query(self, curNode, left, right, ql, qr):
        if left > qr or right < ql:
            return 0
        elif ql <= left and right <= qr:
            return self.tree[curNode]
        else:
            mid = (left + right) // 2
            leftChild = self.query(2 * curNode, left, mid, ql, qr)
            rightChild = self.query(2 * curNode + 1, mid + 1, right, ql, qr)
            return leftChild + rightChild

def sum_between_l_and_r(arr, L, R):
    n = len(arr)
    tree = SegmentTree(arr)
    return tree.query(1, 0, n - 1, L, R)
class SegmentTree {
    private int[] tree;

    public SegmentTree(int[] arr) {
        int n = arr.length;
        tree = new int[4 * n];
        build(arr, 1, 0, n - 1);
    }

    private void build(int[] arr, int curNode, int left, int right) {
        if (left == right) {
            tree[curNode] = arr[left];
        } else {
            int mid = (left + right) / 2;
            build(arr, 2 * curNode, left, mid);
            build(arr, 2 * curNode + 1, mid + 1, right);
            tree[curNode] = tree[2 * curNode] + tree[2 * curNode + 1];
        }
    }

    public void update(int curNode, int left, int right, int idx, int val) {
        if (left == right) {
            tree[curNode] = val;
        } else {
            int mid = (left + right) / 2;
            if (idx <= mid) {
                update(2 * curNode, left, mid, idx, val);
            } else {
                update(2 * curNode + 1, mid + 1, right, idx, val);
            }
            tree[curNode] = tree[2 * curNode] + tree[2 * curNode + 1];
        }
    }

    public int query(int curNode, int left, int right, int ql, int qr) {
        if (ql > right || qr < left) {
            return 0;
        } else if (ql <= left && qr >= right) {
            return tree[curNode];
        } else {
            int mid = (left + right) / 2;
            int leftChild = query(2 * curNode, left, mid, ql, qr);
            int rightChild = query(2 * curNode + 1, mid + 1, right, ql, qr);
            return leftChild + rightChild;
        }
    }
}

public static int sumBetweenLAndR(int[] arr, int L, int R) {
    int n = arr.length;
    SegmentTree tree = new SegmentTree(arr);
    return tree.query(1, 0, n - 1, L, R);
}

时间复杂度为 O(n log n),其中 n 为给定的整数序列的长度。建树的时间复杂度为 O(n log n),单点修改和区间查询的时间复杂度均为 O(log n)。