• [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)



    ┆ 然 ┆   ┆   ┆   ┆ 可 ┆   ┆   ┆ 等 ┆ 暖 ┆
    ┆ 而 ┆ 始 ┆   ┆   ┆ 是 ┆ 将 ┆   ┆ 你 ┆ 一 ┆
    ┆ 你 ┆ 终 ┆ 大 ┆   ┆ 我 ┆ 来 ┆   ┆ 如 ┆ 暖 ┆
    ┆ 没 ┆ 没 ┆ 雁 ┆   ┆ 在 ┆ 也 ┆   ┆ 试 ┆ 这 ┆
    ┆ 有 ┆ 有 ┆ 也 ┆   ┆ 这 ┆ 会 ┆   ┆ 探 ┆ 生 ┆
    ┆ 来 ┆ 来 ┆ 没 ┆   ┆ 里 ┆ 在 ┆   ┆ 般 ┆ 之 ┆
    ┆   ┆   ┆ 有 ┆   ┆   ┆ 这 ┆   ┆ 降 ┆ 凉 ┆
    ┆   ┆   ┆ 来 ┆   ┆   ┆ 里 ┆   ┆ 临 ┆ 薄 ┆
  • 相关阅读:
    离线语音
    云知声语音开发
    自定义View -- 柱状图 我也来自定义个柱状图来玩玩
    android studio中如何替换gradle以防下载卡住
    如何查询当前手机的cpu架构,so库导入工程又出异常了?
    android 学习mvc 和 mvp 和 mvvm参考项目
    【整理】Android中EditText中的InputType类型含义与如何定义( 转 )
    Android点击EditText文本框之外任何地方隐藏键盘的解决办法
    Android开发 adb命令提示:Permission denied (转)
    Node.js-串行化流程控制
  • 原文地址:https://www.cnblogs.com/qiu_jiaqi/p/LeetCode-307.html
Copyright © 2020-2023  润新知