数组的题型最多,而且感觉更多的是考验算法技巧的使用,而非简单的数据结构,毕竟数组也没啥数据结构可言啊,本文是前缀和数组和差分数组
典型题目:
-------------------------------------------
前缀和数组基础,也是leetcode的303题
class NumArray {
public:
vector<int> sum;
NumArray(vector<int>& nums) {
int size = nums.size();
sum.resize(size+1);
sum[0] = 0;
for (int i = 0; i < size; i++) {
sum[i+1] = sum[i] + nums[i];
}
}
int sumRange(int left, int right) {
return sum[right+1] - sum[left];
}
};
/**
* Your NumArray object will be instantiated and called as such:
* NumArray* obj = new NumArray(nums);
* int param_1 = obj->sumRange(left,right);
*/
二维区域检索
偷张图,理解起来会好很多,红色区域的面积等于绿色区域减去蓝色区域减去橙色区域加上粉色区域。把红色区域想象为num(i,j),那么num(i,j) = sum(i,j) - sum(i)(j-1) - sum(i-1)(j) + sum(i-1)(j-1); 变形可得sum(i,j) = sum(i)(j-1) + sum(i-1)(j) -sum(i-1)(j-1)+num(i,j)。
class NumMatrix {
public:
vector<vector<int>> sum;
NumMatrix(vector<vector<int>>& matrix) {
int m = matrix.size();
if (m == 0) return;
int n = matrix[0].size();
sum.resize(m+1, vector<int>(n+1));
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
sum[i+1][j+1] = sum[i+1][j] + sum[i][j+1] - sum[i][j] + matrix[i][j];
}
}
}
int sumRegion(int row1, int col1, int row2, int col2) {
return sum[row2+1][col2+1] - sum[row1][col2+1] - sum[row2+1][col1] + sum[row1][col1];
}
};
/**
* Your NumMatrix object will be instantiated and called as such:
* NumMatrix* obj = new NumMatrix(matrix);
* int param_1 = obj->sumRegion(row1,col1,row2,col2);
*/
和为k的数组,这个理解挺麻烦的,不过做下来感觉hash优化适用所有类似双层嵌套,map通过存储以及其查找速度O(1)特性,优化了j遍历层的速度,结合暴力解法看下。
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
int count = 0;
int size = nums.size();
vector<int> prefix(size+1, 0);
for (int i = 0; i < size; i++) {
prefix[i+1] = prefix[i] + nums[i];
}
for (int i = 0; i < size; i++) {
for (int j = i; j < size; j++) {
if (prefix[j+1] - prefix[i] == k)
count++;
}
}
return count;
}
};
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
int count = 0;
int size = nums.size();
vector<int> prefix(size, 0);
prefix[0] = nums[0];
for (int i = 1; i < size; i++) {
prefix[i] = prefix[i-1] + nums[i];
}
unordered_map<int, int> mp;
mp[0] = 1; //令prefix[-1] = 0; prefix[0] - prefix[-1] = nums[0]
for (int i = 0; i < size; i++) {
if (mp.find(prefix[i] - k) != mp.end()) {
count += mp[prefix[i] - k];
}
//mp实际储存prefix[j],且0<=j<=i
mp[prefix[i]]++;
}
return count;
}
};
差分数组基础
// 差分数组工具类
class Difference {
// 差分数组
vector<int> diff;
/* 输入一个初始数组,区间操作将在这个数组上进行 */
Difference(vector<int> nums) {
diff.resize(nums.size());
// 根据初始数组构造差分数组
diff[0] = nums[0];
for (int i = 1; i < nums.size(); i++) {
diff[i] = nums[i] - nums[i - 1];
}
}
/* 给闭区间 [i,j] 增加 val(可以是负数)*/
public void increment(int i, int j, int val) {
diff[i] += val;
if (j + 1 < diff.length) {
diff[j + 1] -= val;
}
}
/* 返回结果数组 */
vector<int> result() {
vector<int> res; //结果数组
// 根据差分数组构造结果数组
res[0] = diff[0];
for (int i = 1; i < diff.size(); i++) {
res[i] = res[i - 1] + diff[i];
}
return res;
}
}
航班预定统计,增加了个数据抽象思维,把实际场景设计为向量,感觉这种题很容易考,数据抽象是很重要的能力,个人华为机试考过类似的题目。
class Solution {
public:
void increment(vector<int> &diff, int l, int r, int val)
{
diff[l] += val;
if (r+1 < diff.size())
diff[r+1] -= val;
}
vector<int> corpFlightBookings(vector<vector<int>>& bookings, int n) {
vector<int> diff(n, 0);
int size = bookings.size();
for (int i = 0; i < size; i++) {
increment(diff, bookings[i][0]-1, bookings[i][1]-1, bookings[i][2]);
}
for (int i = 1; i < n; i++) {
diff[i]+=diff[i-1];
}
return diff;
}
};
拼车,一样数据抽象
class Solution {
public:
void increment(vector<int> &diff, int l, int r, int val)
{
diff[l] += val;
if (r+1 < diff.size())
diff[r+1] -= val;
}
bool carPooling(vector<vector<int>>& trips, int capacity) {
vector<int> diff(1001,0);
int size = trips.size();
int max = 0;
for (int i = 0; i < size; i++) {
if (trips[i][2] > max) {
max = trips[i][2];
}
increment(diff, trips[i][1], trips[i][2]-1, trips[i][0]);
}
if (diff[0] > capacity) return false;
for (int i = 1; i < max; i++) {
diff[i] += diff[i-1];
if (diff[i] > capacity) return false;
}
return true;
}
};