1.区域和检索 - 数组不可变
给定一个整数数组 nums,求出数组从索引 i 到 j(i ≤ j)范围内元素的总和,包含 i、j 两点。实现 NumArray 类:
NumArray(int[] nums) 使用数组 nums 初始化对象
int sumRange(int i, int j) 返回数组 nums 从索引 i 到 j(i ≤ j)范围内元素的总和,包含 i、j 两点(也就是sum(nums[i], nums[i + 1], … , nums[j]))
考察知识点:前缀和
class NumArray {
public:
vector<int> v;
NumArray(vector<int>& nums) {
v=nums;
for(int i=1;i<v.size();++i)
v[i]+=v[i-1];
}
int sumRange(int left, int right) {
if(left==0) return v[right];
return v[right]-v[left-1];
}
};
或者
class NumArray {
public:
vector<int> sums;
NumArray(vector<int>& nums) {
sums.resize(nums.size() + 1);
for (int i = 0; i < nums.size(); i++)
sums[i + 1] = sums[i] + nums[i];
}
int sumRange(int i, int j) {
return sums[j + 1] - sums[i];
}
};
2.二维区域和检索 - 矩阵不可变
考察知识点:前缀和
class NumMatrix {
public:
vector<vector<int>> v;
NumMatrix(vector<vector<int>>& matrix) {
v=matrix;
for(int i=1;i<v.size();++i)
v[i][0]+=v[i-1][0];
for(int j=1;j<v[0].size();++j)
v[0][j]+=v[0][j-1];
for(int i=1;i<v.size();++i)
for(int j=1;j<v[0].size();++j)
v[i][j]=v[i-1][j]+v[i][j-1]-v[i-1][j-1]+v[i][j];
}
int sumRegion(int row1, int col1, int row2, int col2) {
if(row1>0&&col1>0) return v[row2][col2]-v[row1-1][col2]-v[row2][col1-1]+v[row1-1][col1-1];
if(row1==0&&col1>0) return v[row2][col2]-v[row2][col1-1];
if(row1>0&&col1==0) return v[row2][col2]-v[row1-1][col2];
else return v[row2][col2];
}
};
或者
class NumMatrix {
public:
vector<vector<int>> sums;
NumMatrix(vector<vector<int>>& matrix) {
if (matrix.size() > 0) {
sums.resize(matrix.size() + 1, vector<int>(matrix[0].size() + 1));
for (int i = 0; i < matrix.size(); i++)
for (int j = 0; j < matrix[0].size(); j++)
sums[i+1][j+1]=sums[i][j+1]+sums[i+1][j]-sums[i][j]+matrix[i][j];
}
}
int sumRegion(int row1, int col1, int row2, int col2) {
return sums[row2+1][col2+1]-sums[row1][col2+1]-sums[row2+1][col1]+sums[row1][col1];
}
};
3.区域和检索 - 数组可修改
给你一个数组 nums ,请你完成两类查询,其中一类查询要求更新数组下标对应的值,另一类查询要求返回数组中某个范围内元素的总和。实现 NumArray 类:
NumArray(int[] nums) 用整数数组 nums 初始化对象
void update(int index, int val) 将 nums[index] 的值更新为 val
int sumRange(int left, int right) 返回子数组 nums[left, right] 的总和(即,nums[left] + nums[left + 1], …, nums[right])
考察知识点:线段树
class NumArray {
public:
vector<int> v;
int n;
NumArray(vector<int>& nums) {
n=nums.size();
v.resize(2*n);
for(int i=n,j=0;i<2*n;++i,++j)
v[i]=nums[j];
for(int i=n-1;i>0;--i)
v[i]=v[2*i]+v[2*i+1];
}
void update(int index, int val) {
index+=n;
v[index]=val;
while(index>0) //*
{
int left=index;
int right=index;
if(index%2) left=index-1;
else right=index+1;
index/=2;
v[index]=v[left]+v[right];
}
}
int sumRange(int left, int right) {
left+=n;
right+=n;
int sum=0;
while(left<=right)
{
if(left%2==1)
{
sum+=v[left];
++left;
}
if(right%2==0)
{
sum+=v[right];
--right;
}
left/=2;
right/=2;
}
return sum;
}
};