一,前缀和
1,一维前缀和:
以下是 C++ 中计算一维数组的前缀和的示例代码:
#include <iostream>
#include <vector>
using namespace std;
vector<int> prefixSum(vector<int>& arr) {
int n = arr.size();
vector<int> prefix(n);
prefix[0] = arr[0];
for (int i = 1; i < n; i++) {
prefix[i] = prefix[i-1] + arr[i];
}
return prefix;
}
int main() {
vector<int> arr = {1, 2, 3, 4, 5};
vector<int> prefix = prefixSum(arr);
for (int i = 0; i < prefix.size(); i++) {
cout << prefix[i] << " ";
}
return 0;
}
输出结果为:1 3 6 10 15
这个示例代码定义了一个函数 prefixSum
,输入参数为一个整数数组 arr
,输出一个整数数组 prefix
,存储了 arr
的前缀和。首先创建一个和 arr
大小相同的数组 prefix
,将 arr
的第一个元素赋值给 prefix
的第一个元素。
然后使用遍历的方式计算 prefix
的其他元素。从索引 1 开始遍历 arr
,依次计算每个元素的前缀和,即 prefix[i] = prefix[i-1] + arr[i]
。这里使用了前一个元素的前缀和加上当前元素的值来计算当前元素的前缀和。
最后,在 main
函数中,定义了一个整数数组 arr
,赋值为 1, 2, 3, 4, 5。调用 prefixSum
函数计算数组 arr
的前缀和,然后使用循环遍历输出 prefix
数组的元素,即得到了原数组 arr
的前缀和。
一个优美的算法:
S[i] = a[1] + a[2] + ... a[i]
a[l] + ... + a[r] = S[r] - S[l - 1]
2,二维前缀和:
二维前缀和是指对一个二维数组,计算出该数组中任意子矩阵的元素之和。可以利用动态规划的思想,通过预处理的方式计算出二维前缀和数组。
以下是C++代码示例:
#include <iostream>
#include <vector>
using namespace std;
// 计算二维前缀和
vector<vector<int>> computePrefixSum(vector<vector<int>>& matrix) {
int m = matrix.size();
int n = matrix[0].size();
// 构造二维前缀和数组
vector<vector<int>> prefixSum(m + 1, vector<int>(n + 1, 0));
// 计算每个位置的前缀和
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
prefixSum[i][j] = prefixSum[i-1][j] + prefixSum[i][j-1] - prefixSum[i-1][j-1] + matrix[i-1][j-1];
}
}
return prefixSum;
}
// 计算子矩阵的和
int computeSubMatrixSum(vector<vector<int>>& prefixSum, int row1, int col1, int row2, int col2) {
return prefixSum[row2+1][col2+1] - prefixSum[row1][col2+1] - prefixSum[row2+1][col1] + prefixSum[row1][col1];
}
int main() {
vector<vector<int>> matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
vector<vector<int>> prefixSum = computePrefixSum(matrix);
int subMatrixSum = computeSubMatrixSum(prefixSum, 0, 0, 1, 1);
cout << "subMatrixSum: " << subMatrixSum << endl;
return 0;
}
以上代码中,computePrefixSum
函数用于计算二维前缀和数组,computeSubMatrixSum
函数用于计算子矩阵的和。
在示例中,我们定义了一个3x3的二维数组matrix
,然后通过computePrefixSum
函数计算出二维前缀和数组prefixSum
。接着使用computeSubMatrixSum
函数计算出(0, 0)到(1, 1)的子矩阵的和。最后输出结果为subMatrixSum: 12
。
一个优美的算法:
S[i, j] = 第i行j列格子左上部分所有元素的和
以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为:
S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]
二,差分
C++差分是一种操作,它可以通过对原始数组进行一系列增减操作,从而实现快速地修改数组中某个区间内的元素值。
以下是C++代码示例:
#include <iostream>
#include <vector>
using namespace std;
// 对差分数组进行增减操作
void update(vector<int>& diff, int left, int right, int value) {
diff[left] += value;
if (right + 1 < diff.size()) {
diff[right + 1] -= value;
}
}
// 根据差分数组恢复原始数组
vector<int> restore(vector<int>& diff) {
vector<int> nums(diff.size(), 0);
nums[0] = diff[0];
for (int i = 1; i < diff.size(); i++) {
nums[i] = nums[i - 1] + diff[i];
}
return nums;
}
int main() {
vector<int> nums = {1, 2, 3, 4, 5};
vector<int> diff(nums.size(), 0);
// 对差分数组进行操作,将区间[1, 3]内的元素都增加2
update(diff, 1, 3, 2);
// 恢复原始数组
vector<int> restored = restore(diff);
cout << "Original array:" << endl;
for (int num : nums) {
cout << num << " ";
}
cout << endl;
cout << "Restored array:" << endl;
for (int num : restored) {
cout << num << " ";
}
cout << endl;
return 0;
}
以上代码中,我们首先定义了一个原始数组nums
,然后创建一个和nums
等长的差分数组diff
,并将其初始化为全0。
接着,我们使用update
函数对差分数组进行操作,将区间[1, 3]内的元素都增加2。更新后的差分数组为:[0, 2, 2, 2, 0]。
最后,我们使用restore
函数根据差分数组恢复原始数组,并输出结果。
运行程序,输出结果如下:
Original array:
1 2 3 4 5
Restored array:
1 4 5 6 5
可以看到,经过差分操作和恢复操作后,原始数组的区间[1, 3]内的元素都增加了2。
通过差分操作,我们可以在O(1)的时间复杂度内对原始数组进行一系列修改操作,而无需逐个修改原始数组的元素。这在某些算法问题中非常有用,能够提高代码的效率。
1,一维差分
C++一维差分可以通过对原始数组进行前缀和(或称为前缀和数组)的操作来实现。具体步骤如下:
- 创建一个与原始数组等长的差分数组
diff
,并将其初始化为全0。 - 计算原始数组的前缀和数组
prefix_sum
,其中prefix_sum[i]
表示原始数组中前i个元素的和。 - 对差分数组进行操作:
- 对于原始数组中的某个区间
[left, right]
内的元素,我们将差分数组中的diff[left]
加上value
,diff[right+1]
减去value
。即:diff[left] += value; if (right + 1 < diff.size()) { diff[right + 1] -= value; }
- 对于原始数组中的某个区间
- 根据差分数组恢复原始数组:
- 创建一个与差分数组等长的数组
restored
,并将其初始化为全0。 - 使用一个循环遍历差分数组,计算
restored[i]
的值:restored[i] = restored[i-1] + diff[i];
- 创建一个与差分数组等长的数组
- 返回恢复后的原始数组
restored
。
以下是C++代码示例:
#include <iostream>
#include <vector>
using namespace std;
vector<int> difference(vector<int>& nums) {
int n = nums.size();
vector<int> diff(n, 0);
vector<int> prefix_sum(n, 0);
// Step 2: Calculate prefix sum
prefix_sum[0] = nums[0];
for (int i = 1; i < n; i++) {
prefix_sum[i] = prefix_sum[i - 1] + nums[i];
}
// Step 3: Update difference array
diff[0] = nums[0];
for (int i = 1; i < n; i++) {
diff[i] = prefix_sum[i] - prefix_sum[i - 1];
}
return diff;
}
vector<int> restore(vector<int>& diff) {
int n = diff.size();
vector<int> restored(n, 0);
// Step 4: Restore original array
restored[0] = diff[0];
for (int i = 1; i < n; i++) {
restored[i] = restored[i - 1] + diff[i];
}
return restored;
}
int main() {
vector<int> nums = {1, 3, 4, 2, 5};
// Calculate difference array
vector<int> diff = difference(nums);
// Restore original array
vector<int> restored = restore(diff);
// Print original and restored arrays
cout << "Original array: ";
for (int num : nums) {
cout << num << " ";
}
cout << endl;
cout << "Restored array: ";
for (int num : restored) {
cout << num << " ";
}
cout << endl;
return 0;
}
输出结果为:
Original array: 1 3 4 2 5
Restored array: 1 3 4 2 5
可以看到,经过差分操作和恢复操作后,原始数组与恢复后的数组完全相同。
一个优美的算法:
给区间[l, r]中的每个数加上c:B[l] += c, B[r + 1] -= c
2,二维差分
C++中,可以使用二维差分(Two-dimensional Difference)来求解二维矩阵区域的和或进行区域更新操作。下面是一个简单的示例代码,用于计算二维矩阵区域的和。
#include <iostream>
#include <vector>
using namespace std;
// 计算二维差分矩阵
vector<vector<int>> computeDifference(const vector<vector<int>>& matrix) {
int rows = matrix.size();
int cols = matrix[0].size();
// 初始化二维差分矩阵
vector<vector<int>> difference(rows, vector<int>(cols, 0));
// 计算差分矩阵
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (i == 0 && j == 0) {
difference[i][j] = matrix[i][j];
} else if (i == 0) {
difference[i][j] = matrix[i][j] - matrix[i][j-1];
} else if (j == 0) {
difference[i][j] = matrix[i][j] - matrix[i-1][j];
} else {
difference[i][j] = matrix[i][j] - matrix[i-1][j] - matrix[i][j-1] + matrix[i-1][j-1];
}
}
}
return difference;
}
// 计算二维矩阵区域的和
int computeSum(const vector<vector<int>>& matrix, int row1, int col1, int row2, int col2) {
int rows = matrix.size();
int cols = matrix[0].size();
// 边界处理
if (row1 < 0 || row1 >= rows || row2 < 0 || row2 >= rows || col1 < 0 || col1 >= cols || col2 < 0 || col2 >= cols) {
return 0;
}
// 计算区域和
int sum = matrix[row2][col2];
if (row1 > 0) {
sum -= matrix[row1-1][col2];
}
if (col1 > 0) {
sum -= matrix[row2][col1-1];
}
if (row1 > 0 && col1 > 0) {
sum += matrix[row1-1][col1-1];
}
return sum;
}
int main() {
vector<vector<int>> matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
vector<vector<int>> difference = computeDifference(matrix);
int sum = computeSum(difference, 1, 1, 2, 2);
cout << "Sum: " << sum << endl;
return 0;
}
在上面的示例中,computeDifference
函数用于计算二维差分矩阵,computeSum
函数用于计算二维矩阵区域的和。可以根据需要修改输入矩阵和区域的起始、终止坐标,以适应不同的求解问题。
一个优美的算法:
给以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵中的所有元素加上c:
S[x1, y1] += c, S[x2 + 1, y1] -= c, S[x1, y2 + 1] -= c, S[x2 + 1, y2 + 1] += c