这里是Themberfue
【模板】前缀和
题目解析
本题就是求给定两个索引的之间的数组和,比如:给定1和3下标索引,那么就求出,下标1到下标3所有元素的和即可。
算法讲解
· 利用前缀和可以快速求出数组中某一连续区间的和。
· 所以我们需要先预处理出来一个前缀和数组 dp[],dp[i] 表示 [1, i]这个区间数组的和。
· 根据推导,我们可以得出状态转移方程,也就是当前位置的前缀和等于上一个位置的前缀和加上当前位置数组的元素。即 dp[i] = dp[i - 1] + arr[i]。
· 为了防止 dp 数组下标越界访问,我们一般以 1 为起点计数。所以记得给 dp 数组的下标0位置初始为0。
· 但现在我们要求给定区间的和,有了 dp 数组就好求了,比如要求求出 [2, 5]的下标和,那么其实就是 dp[5] - dp[1]。
· 总结公式:[left, right] => dp[right] - dp[left - 1]
编写代码
java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(), q = sc.nextInt();
// 创建前缀和数组
long[] dp = new long[n + 1];
for (int i = 1; i <= n; i++) {
dp[i] = dp[i - 1] + sc.nextInt();
}
// 使用前缀和数组
for (int i = 0; i < q; i++) {
int left = sc.nextInt(), right = sc.nextInt();
System.out.println(dp[right] - dp[left - 1]);
}
}
}
【模板】二维前缀和
题目解析
此题与上题类似,不过就是从一维数组变成了二维数组。 给定四个索引,表示数组的横排索引以及纵排索引,然后就是这个范围所代表的矩形区域的和。
算法讲解
· 本题的 dp[i][j] 表示 [1][1]到dp[i][j] 所构成的矩形区域的和。
· 根据数形结合来推导出状态转移方程。
· dp[i][j] = dp[i - 1][j] + dp[i][j - 1] + arr[i][j] - dp[i - 1][j - 1]
· 同样的,为了防止数组下标越界访问,也是从1下标开始计数。
· 利用数形结合,同样推导出该公式。
· ret = dp[x2][y2] - dp[x1 - 1][y2] - dp[x2][y1 - 1] + dp[x1 - 1][y1 - 1]
编写代码
java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(), m = sc.nextInt(), q = sc.nextInt();
// 创建一个二维前缀和数组
long[][] dp = new long[n + 1][m + 1];
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
dp[i][j] = dp[i - 1][j] + dp[i][j-1] + sc.nextInt() - dp[i-1][j-1];
}
}
// 使用二位前缀数组
for (int i = 0; i < q; i++) {
int x1 = sc.nextInt(), y1 = sc.nextInt(), x2 = sc.nextInt(), y2 = sc.nextInt();
System.out.println(dp[x2][y2] - dp[x1 - 1][y2] - dp[x2][y1 - 1] + dp[x1 - 1][y1 - 1]);
}
}
}
寻找数组的中心下标
题目解析
返回一个下标,这个下标(不包括它自己)左边所有元素的和等于右边所有元素的和。
算法讲解
· 题目出现了某一个区间内的和,那应该想到使用前缀和。
· 左边所有元素的和便使用前缀和,但这个前缀和不应该包括它自身。
· 但右边所有元素的和应该使用后缀和,且这个后缀和也不应该包括它自身。
· 根据图示,前缀和数组应该从前往后遍历,公式为:f[i] = f[i - 1] + arr[i - 1],为了防止越界访问,前缀和数组的第0个位置记得初始化
· 根据图示,后缀和数组一个从后往前遍历,公式为:g[i] = g[i + 1] + arr[i + 1],为了防止越界访问,前缀和数组的第n - 1个位置记得初始化。
· 最后如果某一位置的前缀和和后缀和相同,那么该下标就满足题意。
编写代码
java
class Solution {
public int pivotIndex(int[] nums) {
int n = nums.length;
// 创建前缀和数组以及后缀和数组
int[] f = new int[n];
for (int i = 1; i < n; i++)
f[i] = f[i - 1] + nums[i - 1];
int[] g = new int[n];
for (int i = n - 2; i >= 0; i--)
g[i] = g[i + 1] + nums[i + 1];
// 使用前缀和数组以及后缀和数组
for (int i = 0; i < n; i++) {
if (f[i] == g[i])
return i;
}
return -1;
}
}
除自身以外数组的乘积
题目解析
本题表示对于当前下标,除了它自身以外的元素,返回其余元素的乘积。
算法讲解
· 这题与上题类似,只不过变成了前缀积和后缀积。
· 填完前缀积和后缀积后,之间返回它们对于下标的积即可。
编写代码
java
class Solution {
public int[] productExceptSelf(int[] nums) {
int len = nums.length;
// 创建前缀积数组以及后缀积数组
int[] f = new int[len];
f[0] = 1;
for (int i = 1; i < len; i++) {
f[i] = f[i - 1] * nums[i - 1];
}
int[] g = new int[len];
g[len - 1] = 1;
for (int i = len - 2; i >= 0; i--) {
g[i] = g[i + 1] * nums[i + 1];
}
int[] ret = new int[len];
// 使用前缀积数组以及后缀积数组
for (int i = 0; i < len; i++) {
ret[i] = f[i] * g[i];
}
return ret;
}
}
好了,以上就是今天内容的全部讲解,如果有不懂的地方,随时私聊😘
我们下半部分见😁