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

    传送门:[LeetCode] 303. 区域和检索 - 数组不可变

    题目描述

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

    说明:

    • 你可以假设数组不可变。
    • 会多次调用 sumRange 方法。

    示例 :

    给定 nums = [-2, 0, 3, -5, 2, -1],求和函数为 sumRange()

    sumRange(0, 2) -> 1
    sumRange(2, 5) -> -1
    sumRange(0, 5) -> -3

    分析与代码

    • 直接求和是超时的,我们可以用数组保存前缀和。

    解法一、前缀和数组

    • 创建一个长度为 nums.length + 1 的数组 sum,下标为 n 则保存前 n 个数的和。第一个为 0,最后一个为总和。
    • sumRange(i, j) 则返回 sum[j + 1] - sum[i]。sum[j + 1]保存下标 0 到 j 的数之和,而 sum[i] 保存下标 0 到 i - 1的数之和,相减则为下标 i 到 j 的数之和。

    代码:

    public class NumArray {
        private int[] sum;
    
        public NumArray(int[] nums) {
            sum = new int[nums.length + 1];
            for (int i = 0; i < nums.length; i++) {
                sum[i + 1] = sum[i] + nums[i];
            }
        }
    
        public int sumRange(int i, int j) {
            return sum[j + 1] - sum[i];
        }
    }
    

    解法二、线段树

    了解线段树

    • 这题线段树只涉及构建和查询。

    代码:

    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 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 = getRightChileIndex(treeIndex);
            int mid = (treeLeft + treeRight) >>> 1;
            build(leftChildIndex, treeLeft, mid);
            build(rightChildIndex, mid + 1, treeRight);
            tree[treeIndex] = tree[leftChildIndex] + tree[rightChildIndex];
        }
    
        private int queryRange(int treeIndex, int treeLeft, int treeRight, int queryLeft, int queryRight) {
            if (treeLeft == queryLeft && treeRight == queryRight) {
                return tree[treeIndex];
            }
            int leftChildIndex = getLeftChildIndex(treeIndex);
            int rightChildIndex = getRightChileIndex(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 getRightChileIndex(int index) {
            return 2 * index + 2;
        }
    }
    

    小结

    都用数组保存了累加和,空间换取时间。



    ┆ 然 ┆   ┆   ┆   ┆ 可 ┆   ┆   ┆ 等 ┆ 暖 ┆
    ┆ 而 ┆ 始 ┆   ┆   ┆ 是 ┆ 将 ┆   ┆ 你 ┆ 一 ┆
    ┆ 你 ┆ 终 ┆ 大 ┆   ┆ 我 ┆ 来 ┆   ┆ 如 ┆ 暖 ┆
    ┆ 没 ┆ 没 ┆ 雁 ┆   ┆ 在 ┆ 也 ┆   ┆ 试 ┆ 这 ┆
    ┆ 有 ┆ 有 ┆ 也 ┆   ┆ 这 ┆ 会 ┆   ┆ 探 ┆ 生 ┆
    ┆ 来 ┆ 来 ┆ 没 ┆   ┆ 里 ┆ 在 ┆   ┆ 般 ┆ 之 ┆
    ┆   ┆   ┆ 有 ┆   ┆   ┆ 这 ┆   ┆ 降 ┆ 凉 ┆
    ┆   ┆   ┆ 来 ┆   ┆   ┆ 里 ┆   ┆ 临 ┆ 薄 ┆
  • 相关阅读:
    [51NOD]大数加法(模拟)
    LCS记录路径
    BISTU-(1)-4-17-2016
    [CF580B]Kefa and Company(滑动窗口)
    [CF660C]Hard Process(尺取法)
    [POJ3061]Subsequence(二分,前缀和)
    [HDOJ2602]Bone Collector(01背包)
    [HDOJ1171]Big Event in HDU(01背包)
    [HDOJ2512]一卡通大冒险(DP)
    hdu 1269 迷宫城堡 最简单的联通图题 kosaraju缩点算法
  • 原文地址:https://www.cnblogs.com/qiu_jiaqi/p/LeetCode-303.html
Copyright © 2011-2022 走看看