zoukankan      html  css  js  c++  java
  • [LeetCode] 307. 区域和检索

    传送门:[LeetCode] 307. 区域和检索 - 数组可修改

    题目描述

    给定一个整数数组 nums,求出数组从索引 ij (ij) 范围内元素的总和,包含 i, j 两点。

    update(i, val) 函数可以通过将下标为 i 的数值更新为 val,从而对数列进行修改。

    说明:

    • 数组仅可以在 update 函数下进行修改。
    • 你可以假设 update 函数与 sumRange 函数的调用次数是均匀分布的。

    示例 :

    Given nums = [1, 3, 5]

    sumRange(0, 2) -> 9
    update(1, 2)
    sumRange(0, 2) -> 8

    分析与代码

    解法一、暴力

    • 就是普通数组,求和也是直接 for 循环。

    代码:

    class NumArray {
        private int[] data;
    
        public NumArray(int[] nums) {
            data = nums.clone();
        }
    
        public void update(int i, int val) {
            data[i] = val;
        }
    
        public int sumRange(int i, int j) {
            int sum = 0;
            while (i <= j) {
                sum += data[i++];
            }
            return sum;
        }
    }
    

    解法二、线段树

    了解线段树

    • 线段树的构建、查询、单点更新。

    代码:

    class NumArray {
        private int[] data;
        private int[] tree;
    
        public NumArray(int[] nums) {
            if (nums.length == 0){
                return;
            }
            data = nums.clone();
            tree = new int[4 * nums.length];
            build(0, 0, nums.length - 1);
        }
    
        public void update(int i, int val) {
            data[i] = val;
            update(0, 0, data.length - 1, i, val);
    
        }
    
        public int sumRange(int i, int j) {
            return queryRange(0, 0, data.length - 1, i, j);
        }
    
        private void build(int treeIndex, int treeLeft, int treeRight) {
            if (treeLeft == treeRight) {
                tree[treeIndex] = data[treeLeft];
                return;
            }
            int leftChildIndex = getLeftChildIndex(treeIndex);
            int rightChildIndex = getRightChildIndex(treeIndex);
            int mid = (treeLeft + treeRight) >>> 1;
            build(leftChildIndex, treeLeft, mid);
            build(rightChildIndex, mid + 1, treeRight);
            tree[treeIndex] = tree[leftChildIndex] + tree[rightChildIndex];
        }
    
        private void update(int treeIndex, int treeLeft, int treeRight, int index, int val) {
            if (treeLeft == treeRight) {
                tree[treeIndex] = val;
                return;
            }
            int leftChildIndex = getLeftChildIndex(treeIndex);
            int rightChildIndex = getRightChildIndex(treeIndex);
            int mid = (treeLeft + treeRight) >>> 1;
            if (index > mid) {
                update(rightChildIndex, mid + 1, treeRight, index, val);
            } else {
                update(leftChildIndex, treeLeft, mid, index, val);
            }
            tree[treeIndex] = tree[leftChildIndex] + tree[rightChildIndex];
        }
    
        private int queryRange(int treeIndex, int treeLeft, int treeRight, int queryLeft, int queryRight) {
            if (queryLeft == treeLeft && queryRight == treeRight) {
                return tree[treeIndex];
            }
            int leftChildIndex = getLeftChildIndex(treeIndex);
            int rightChildIndex = getRightChildIndex(treeIndex);
            int mid = (treeLeft + treeRight) >>> 1;
            if (queryLeft > mid) {
                return queryRange(rightChildIndex, mid + 1, treeRight, queryLeft, queryRight);
            } else if (queryRight <= mid) {
                return queryRange(leftChildIndex, treeLeft, mid, queryLeft, queryRight);
            }
            int leftResult = queryRange(leftChildIndex, treeLeft, mid, queryLeft, mid);
            int rightResult = queryRange(rightChildIndex, mid + 1, treeRight, mid + 1, queryRight);
            return leftResult + rightResult;
        }
    
        private int getLeftChildIndex(int index) {
            return 2 * index + 1;
        }
    
        private int getRightChildIndex(int index) {
            return 2 * index + 2;
        }
    }
    

    小结

    线段树查询和更新的时间复杂度都是O(logn),而普通数组的方法,更新的时间复杂度为O(1),查询为O(n)



    ┆ 然 ┆   ┆   ┆   ┆ 可 ┆   ┆   ┆ 等 ┆ 暖 ┆
    ┆ 而 ┆ 始 ┆   ┆   ┆ 是 ┆ 将 ┆   ┆ 你 ┆ 一 ┆
    ┆ 你 ┆ 终 ┆ 大 ┆   ┆ 我 ┆ 来 ┆   ┆ 如 ┆ 暖 ┆
    ┆ 没 ┆ 没 ┆ 雁 ┆   ┆ 在 ┆ 也 ┆   ┆ 试 ┆ 这 ┆
    ┆ 有 ┆ 有 ┆ 也 ┆   ┆ 这 ┆ 会 ┆   ┆ 探 ┆ 生 ┆
    ┆ 来 ┆ 来 ┆ 没 ┆   ┆ 里 ┆ 在 ┆   ┆ 般 ┆ 之 ┆
    ┆   ┆   ┆ 有 ┆   ┆   ┆ 这 ┆   ┆ 降 ┆ 凉 ┆
    ┆   ┆   ┆ 来 ┆   ┆   ┆ 里 ┆   ┆ 临 ┆ 薄 ┆
  • 相关阅读:
    【洛谷5052】[COCI2017-2018#7] Go(区间DP)
    【洛谷6564】[POI2007] 堆积木KLO(树状数组优化DP)
    【洛谷6940】[ICPC2017 WF] Visual Python++(扫描线)
    【洛谷6939】[ICPC2017 WF] Tarot Sham Boast(PGF结论题)
    【洛谷4123】[CQOI2016] 不同的最小割(最小割树)
    初学最小割树
    【洛谷6122】[NEERC2016] Mole Tunnels(模拟费用流)
    【洛谷6936】[ICPC2017 WF] Scenery(思维)
    【洛谷2805】[NOI2009] 植物大战僵尸(最大权闭合子图)
    【洛谷1393】Mivik 的标题(容斥+border性质)
  • 原文地址:https://www.cnblogs.com/qiu_jiaqi/p/LeetCode-307.html
Copyright © 2011-2022 走看看