文章目录
- 前缀和模板
- 724. 寻找数组的中心下标
- 238. 除自身以外数组的乘积
- 560. 和为 K 的子数组
- 974. 和可被 K 整除的子数组
- 525. 连续数组
- 1314. 矩阵区域和
前缀和模板
一维前缀和:
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt(),q = scan.nextInt();
int[] arr = new int[n + 1];
long[] dp = new long[n + 1];
for(int i = 1;i <= n;i++) {
arr[i] = scan.nextInt();
dp[i] = dp[i - 1] + arr[i];
}
while(q > 0) {
int l = scan.nextInt(),r = scan.nextInt();
System.out.println(dp[r] - dp[l - 1]);
q--;
}
}
}
二维前缀和:
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt(),m = scan.nextInt(),q = scan.nextInt();
int[][] arr = new int[n + 1][m + 1];
long[][] dp = new long[n + 1][m + 1];
for(int i = 1;i <= n;i++) {
for(int j = 1;j <= m;j++) {
arr[i][j] = scan.nextInt();
dp[i][j] = arr[i][j] + dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1];
}
}
while(q > 0) {
int x1 = scan.nextInt(),y1 = scan.nextInt();
int x2 = scan.nextInt(),y2 = scan.nextInt();
System.out.println(dp[x2][y2] - dp[x1 - 1][y2] - dp[x2][y1 - 1] + dp[x1 - 1][y1 - 1]);
q--;
}
}
}
724. 寻找数组的中心下标
给你一个整数数组 nums ,请计算数组的 中心下标 。
数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。
如果中心下标位于数组最左端,那么左侧数之和视为 0 ,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。
如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回 -1 。
class Solution {
public int pivotIndex(int[] nums) {
int n = nums.length;
int[] f = new int[n];
int[] g = new int[n];
for(int i = 1;i < n;i ++) {
f[i] = f[i - 1] + nums[i - 1];
}
for(int j = n - 2;j >= 0;j--) {
g[j] = g[j + 1] + nums[j + 1];
}
for(int i = 0;i < n;i++) {
if(f[i] == g[i]) {
return i;
}
}
return -1;
}
}
238. 除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。
题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。
请不要使用除法,且在 O(n) 时间复杂度内完成此题。
class Solution {
public int[] productExceptSelf(int[] nums) {
int n = nums.length;
int[] f = new int[n];
int[] g = new int[n];
f[0] = 1;
g[n - 1] = 1;
for(int i = 1;i < n;i++) {
f[i] = f[i - 1] * nums[i - 1];
}
for(int i = n - 2;i >= 0;i--) {
g[i] = g[i + 1] * nums[i + 1];
}
int[] ret = new int[n];
for(int i = 0;i < n;i++) {
ret[i] = f[i] * g[i];
}
return ret;
}
}
560. 和为 K 的子数组
给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的连续子数组的个数 。
class Solution {
public int subarraySum(int[] nums, int k) {
Map<Integer,Integer> hash = new HashMap<>();
hash.put(0,1);
int sum = 0, ret = 0;
for(int x : nums) {
sum += x;
ret += hash.getOrDefault(sum - k,0);
hash.put(sum,hash.getOrDefault(sum,0) + 1);
}
return ret;
}
}
974. 和可被 K 整除的子数组
给定一个整数数组 nums 和一个整数 k ,返回其中元素之和可被 k 整除的(连续、非空) 子数组 的数目。
子数组 是数组的 连续 部分。
class Solution {
public int subarraysDivByK(int[] nums, int k) {
Map<Integer,Integer> hash = new HashMap<>();
hash.put(0,1);
int sum = 0,ret = 0;
for(int x : nums) {
sum += x;
int r = (sum % k + k) % k;
ret += hash.getOrDefault(r,0);
hash.put(r,hash.getOrDefault(r,0) + 1);
}
return ret;
}
}
525. 连续数组
给定一个二进制数组 nums , 找到含有相同数量的 0 和 1 的最长连续子数组,并返回该子数组的长度。
class Solution {
public int findMaxLength(int[] nums) {
Map<Integer,Integer> hash = new HashMap<>();
hash.put(0,-1); //默认存在一个前缀和为0的情况
int sum = 0,ret = 0;
for(int i = 0; i < nums.length;i++) {
sum += (nums[i] == 0 ? -1 : 1);
if(hash.containsKey(sum)) {
ret = Math.max(ret,i - hash.get(sum));
} else {
hash.put(sum,i);
}
}
return ret;
}
}
1314. 矩阵区域和
给你一个 m x n 的矩阵 mat 和一个整数 k ,请你返回一个矩阵 answer ,其中每个 answer[i][j] 是所有满足下述条件的元素 mat[r][c] 的和:
i - k <= r <= i + k, j - k <= c <= j + k 且(r, c) 在矩阵内。
class Solution {
public int[][] matrixBlockSum(int[][] mat, int k) {
int m = mat.length,n = mat[0].length;
int[][] dp = new int[m + 1][n + 1];
for(int i = 1;i <= m;i++) {
for(int j = 1;j <= n;j++) {
dp[i][j] = mat[i - 1][j - 1] + dp[i - 1][j] + dp[i][j - 1]
- dp[i - 1][j - 1];
}
}
int[][] ret = new int[m][n];
for(int i = 0;i < m;i++) {
for(int j = 0;j < n;j++) {
int x1 = Math.max(0,i - k) + 1;
int y1 = Math.max(0,j - k) + 1;
int x2 = Math.min(m - 1,i + k) + 1;
int y2 = Math.min(n - 1,j + k) + 1;
ret[i][j] = dp[x2][y2] - dp[x1 - 1][y2] - dp[x2][y1 - 1] + dp[x1-1][y1-1];
}
}
return ret;
}
}