由于水平原因,博客大部分内容摘抄于网络,如有错误或者侵权请指出,本人将尽快修改

一维前缀和

前缀和:

就是一个数组,要快速静态查询区间和,我们只要处理一个数组时A[i]=a[0]+a[1]+a[2]+...+a[i-1].

A[0]=0

A[1]=a[0]

A[2]=a[1]+a[0]

A[3]=a[2]+a[1]+a[0]

A[4]=a[3]+a[2]+a[1]+a[0]

......

例如:求[0,3]的区间和,A[4]-A[0]=a[0]+a[1]+a[2]+a[3]=a[0]+a[1]+a[2]+a[3]-(a[0])

那么查询区间[l,r]的时候只要输出A[r+1]-A[l].

那么这是时候预处理是O(n)的,查询一次是O(1).

在很多情况下这种算法都是可行的,但是必须满足区间减法的性质.

代码预处理如下:

for (int i=1;i<=n;i++)
A[i]=A[i-1]+a[i];

303. 区域和检索 - 数组不可变

题目描述

给定一个整数数组 nums,求出数组从索引 left 到索引 right(包含 leftright)之间所有元素的和,包含多次这样的查询。

示例:

NumArray numArray = new NumArray([1, 3, 5]);
numArray.sumRange(0, 2); // 返回 9,即 nums[0] + nums[1] + nums[2]
numArray.sumRange(2, 2); // 返回 5,即 nums[2]
numArray.sumRange(0, 1); // 返回 4,即 nums[0] + nums[1]

解答

class NumArray {
    int A[];
    public NumArray(int[] nums) {
        A = new int[nums.length + 1];
        for (int i = 1; i <= nums.length; i++) {
            A[i] = nums[i - 1] + A[i - 1];
        }
    }

    public int sumRange(int l, int r) {
        return A[r + 1] - A[l];
    }
}

303. 区域和检索 - 数组不可变(变种题:累加和为给定值的最长子数组长度)

题目描述

给定一个无序数组 arr,其中元素可以是正数、负数或零。再给定一个整数 k,要求找出 arr 中所有子数组中累加和为 k 的最长子数组长度。

输入描述

  • 第一行包含两个整数 Nk,其中 N 表示数组的长度,k 是给定的累加和。
  • 第二行包含 N 个整数,表示数组 arr 内的元素。

输出描述

  • 输出一个整数,表示累加和为 k 的最长子数组的长度。

示例

示例1

输入:
5 0
1 -2 1 1 1

输出:
3

解释

在示例1中,数组 arr[1, -2, 1, 1, 1],目标累加和 k0

  • 子数组 [1, -2, 1] 的累加和为 0,长度为 3
  • 其他子数组如 [1, 1, -1] 的累加和也为 0,但长度为 3,没有更长的子数组满足条件。
  • 因此,最长子数组的长度为 3

解题思路

这个问题可以使用前缀和(Prefix Sum)和哈希表(HashMap)来高效解决。

  1. 初始化数组的前缀和
  2. 前缀和,index 加入map中,并计算出最大长度。index使用前最早前缀和的位置。
    public static int maxKLen(int nums[], int k) {
        int[] A = new int[nums.length + 1];
        for (int i = 1; i <= nums.length; i++) {
            A[i] = nums[i - 1] + A[i - 1];
        }
        Map<Integer,Integer> map = new HashMap<>();
        map.put(0,0);
        int maxLen = 0;
        for (int j = 1; j < A.length; j++) {
            int target = A[j]-k;
            if (map.containsKey(target)){
            maxLen = Math.max(j-map.get(target),maxLen);
            }
            map.putIfAbsent(A[j],j);
        }
        return maxLen;
    }
  1. 和为 K 的子数组

给定一个整数数组 nums 和一个整数 k,你需要找出该数组中和为 k 的连续子数组的个数。

示例

示例 1:

输入: nums = [1,1,1], k = 2
输出: 2
解释: [1,1] 和 [1,1] 是两个和为 2 的子数组。

示例 2:

输入: nums = [1,2,3], k = 3
输出: 2
解释: [1,2] 和 [3] 是两个和为 3 的子数组。

解题思路

  1. 前缀和 + 哈希表
  • 使用一个哈希表(字典)来存储从数组起始位置到当前位置的前缀和及其出现的次数。
  • 遍历数组,计算当前位置的前缀和 prefix_sum
  • 检查 prefix_sum - k 是否在哈希表中,如果在,则说明存在一个子数组的和为 k
  • 更新哈希表,将当前的前缀和及其出现次数存入。
  • 时间复杂度为 O(n),空间复杂度为 O(n)。
    public int subarraySum(int[] nums, int k) {
        int[] A = new int[nums.length + 1];
        for (int i = 1; i <= nums.length; i++) {
            A[i] = nums[i - 1] + A[i - 1];
        }
        Map<Integer,Integer> map = new HashMap<>();
        map.put(0,1);
        int cnt = 0;
        for (int j = 1; j < A.length; j++) {
            int target = A[j]-k;
            if (map.containsKey(target)){
                cnt += map.get(target);
            }
            map.put(A[j],map.getOrDefault(A[j],0)+1);
        }
        return cnt;
    }

题目描述

给定一个无序数组 arr,其中元素可以是正数、负数或零。要求找出 arr 中所有子数组中,正数与负数个数相等的最长子数组的长度。

输入描述

  • 第一行一个整数 N,表示数组的长度。
  • 接下来一行有 N 个数,表示数组 arr 中的元素。

输出描述

  • 输出一个整数,表示满足条件的最长子数组的长度。

示例

示例1

输入:
5
1 -2 1 1 1

输出:
2

解题思路

要解决这个问题,我们可以利用前缀和与哈希表的方法,但需要对“前缀和”进行一定的抽象和转化。在这里,我们可以将正数视为 +1,负数视为 -1,零则不影响计数,可以视为 0。计算数组长度时要包含0.

接下来,我们计算一个“特殊的前缀和”,它表示从数组起始位置到当前位置的正数与负数的“差值”(正数视为 +1,负数视为 -1)。当我们找到两个相同的前缀和值时,它们之间的子数组中正数与负数的个数必然相等(因为它们的差值都是零)。

    public static int subArray(int[] nums) {
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] > 0) {
                nums[i] = 1;
            } else if (nums[i] < 0) {
                nums[i] = -1;
            }
        }
        int[] A = new int[nums.length + 1];
        for (int i = 1; i <= nums.length; i++) {
            A[i] = nums[i - 1] + A[i - 1];
        }
        Map<Integer, Integer> map = new HashMap<>();
        map.put(0, 0);
        int maxLen = 0;
        for (int j = 1; j < A.length; j++) {
            int target = A[j];
            if (map.containsKey(target)) {
                maxLen = Math.max(j - map.get(target), maxLen);
            }
            map.putIfAbsent(A[j], j);
        }
        return maxLen;
    }
posted @ 2019-01-24 16:20  小纸条  阅读(245)  评论(0)    收藏  举报