数组理论基础总结:
1.数组是存放在连续内存空间上的相同数据类型数据的集合
- 数组下标从0开始
- 数组内存空间的地址是连续的
2.数组的元素不能删除,只能覆盖
3.二维数组的内存空间地址是连续的吗?
不同编程语言的内存管理是不一样的,在C++中二维数组内存空间是连续分布的
数组的经典题目:
/*
采用左闭右闭([left,right])写法
while(left <= right), 因为 left == right 是有意义的
if(nums[mid] > target) right = mid - 1,因为当前这个nums[mid]值一定不是target
*/
class Solution {
public:
int search(vector<int>& nums, int target) {
int leftIndex = 0;
int rightIndex = nums.size() - 1;
while (leftIndex <= rightIndex) {
int midIndex = leftIndex + (rightIndex - leftIndex) / 2;
if (nums[midIndex] == target) {
return midIndex;
} else if (nums[midIndex] < target) {
leftIndex = midIndex + 1;
} else {
rightIndex = midIndex - 1;
}
}
return -1; // Target not found
}
};
/*
双指针法:通过一个快指针和慢指针在一个for循环下完成两个for循环的工作
· 快指针:遍历原数组,寻找新数组的元素
· 慢指针:指向新数组下标的位置
*/
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slowIndex = 0;
for(int fastIndex = 0; fastIndex < nums.size(); ++fastIndex) {
if(nums[fastIndex] != val) {
nums[slowIndex++] = nums[fastIndex];
}
}
return slowIndex;
}
};
/*
数组其实是有序的,只不过负数平方之后可能成为最大数了
那么数组平方的最大数就在数组的两端,不是最左边就是最右边,不可能是中间
此时可以考虑双指针法,i指向起始位置,k指向终止位置
*/
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int k = nums.size() - 1;
vector<int> result(nums.size(),0);
for(int i = 0, j = nums.size() - 1; i <= j;) {
if(nums[i] * nums[i] < nums[j] * nums[j]) {
result[k--] = nums[j] * nums[j];
j--;
} else {
result[k--] = nums[i] * nums[i];
i++;
}
}
return result;
}
};
/*
滑动窗口:不断调节子序列的起始位置和终止位置,从而得出我们想要的结果
· 窗口:满足其和 ≥ target 的长度最小的连续子数组
· 窗口的起始位置:如果当前窗口的值 ≥ target,窗口就要向前移动了(收缩窗口)
· 窗口的结束位置:窗口的结束位置就是遍历数组的指针
*/
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int left = 0, right = 0, current_sum = 0;
int min_length = INT_MAX;
for(; right < nums.size(); ++right) {
current_sum += nums[right];
while(current_sum >= target) {
min_length = min(min_length,right - left + 1);
current_sum -= nums[left++];
}
}
return (min_length == INT_MAX) ? 0 : min_length;
}
};
/*
循环不变量原则,模拟顺时针画矩阵的过程
· 填充上行->从左到右
· 填充右列->从上到下
· 填充下行->从右到左
· 填充左列->从下到上
*/
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n,vector<int>(n,0));
int startX = 0,startY = 0; // 定义每循环一圈的起始位置
int mid = n / 2; // 矩阵中心位置,如 n = 3,那么中心位置为(1,1)
int loop = n / 2; // 循环的圈数
int offset = 1; // 控制每一条边遍历的长度
int count = 1; // 用来给矩阵中每一个空格赋值
int i,j;
while(loop--) {
i = startX;
j = startY;
// 模拟转圈(左闭右开)
// Top:从左到右
for(j;j < n - offset;j++) {
res[i][j] = count++;
}
// Right:从上到下
for(i;i < n - offset;i++) {
res[i][j] = count++;
}
// Bottom:从右到左
for(j;j > startY;j--) {
res[i][j] = count++;
}
// Left:从下到上
for(i;i > startX;i--) {
res[i][j] = count++;
}
// 往后循环转圈,起始位置+1
startX++;
startY++;
// 边距长度+1
offset++;
}
// 如果 n 为奇数,需要单独给矩阵中心空格赋值
if(n % 2) {
res[mid][mid] = count;
}
return res;
}
};
/*
看到本题,我当时的想法也是那么简单,直接获取区间累加不就行了
提交后发现超时了,该算法的时间复杂度是O(n * m) m 是查询的次数
*/
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n, a, b;
cin >> n;
vector<int> vec(n);
for (int i = 0; i < n; i++) cin >> vec[i];
while (cin >> a >> b) {
int sum = 0;
// 累加区间 a 到 b 的和
for (int i = a; i <= b; i++) sum += vec[i];
cout << sum << endl;
}
}
/*
前缀和:重复利用计算过的子数组之和,从而降低区间查询需要累加计算的次数
例如,我们要统计 vec[i] 这个数组上的区间和,我们先做累加,即p[i]表示下标0到vec[i]累加之和
vec[i]: 1 2 3 3 2 1 2
p[i] : 1 3 6 9 11 12 14
*/
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n, a, b;
cin >> n;
vector<int> vec(n);
vector<int> p(n);
int presum = 0;
for (int i = 0; i < n; i++) {
cin >> vec[i];
presum += vec[i];
p[i] = presum;
}
while (cin >> a >> b) {
int sum;
if (a == 0) sum = p[b];
else sum = p[b] - p[a - 1];
cout << sum << endl;
}
}