1.二分查找 O(logn)
算法前提:有序数组
算法核心:理解对查找区间的定义(正确答案所在区间),在循环中根据区间定义做边界处理
class Solution {
public:
int search(vector<int>& nums, int target) {
// 定义target在[left, right]区间
int min = 0, max = nums.size() - 1, mid;
// 闭区间内min == max合法,需要取等号
while(min <= max){
// 防止大数溢出
mid = min + (max - min) / 2;
if(nums[mid] > target){
max = mid - 1;
}
else if(nums[mid] < target){
min = mid + 1;
}
else return mid;
}
return -1;
}
};
拓展题:
35. 搜索插入位置 - 力扣(LeetCode)(注意对插入情况的分析讨论)
34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)
2.排序 O(nlogn)
1.快速排序
void quick_sort(int q[], int l, int r)
{
if (l >= r) return;
int i = l - 1, j = r + 1, x = q[l + r >> 1];
while (i < j)
{
do i ++ ; while (q[i] < x);
do j -- ; while (q[j] > x);
if (i < j) swap(q[i], q[j]);
}
// 分治
quick_sort(q, l, j);
quick_sort(q, j + 1, r);
}
2.归并排序
void merge_sort(int q[], int l, int r)
{
if (l >= r) return;
int mid = l + r >> 1;
merge_sort(q, l, mid), merge_sort(q, mid + 1, r);
int k = 0, i = l, j = mid + 1;
while (i <= mid && j <= r)
if (q[i] <= q[j]) tmp[k ++ ] = q[i ++ ];
else tmp[k ++ ] = q[j ++ ];
while (i <= mid) tmp[k ++ ] = q[i ++ ];
while (j <= r) tmp[k ++ ] = q[j ++ ];
for (i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j];
}
3.双指针 O(n)
int removeElement(vector<int>& nums, int val) {
// 慢指针记录个数
int slowIndex = 0;
// 快指针扫描数组
for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) {
// 把符合要求的数前移(所有符合要求的数都在慢指针后面,不会产生覆盖问题)
if (val != nums[fastIndex]) {
nums[slowIndex++] = nums[fastIndex];
}
}
return slowIndex;
}
4.滑动窗口 O(n)
int minSubArrayLen(int target, vector<int>& nums) {
// 滑动窗口
// j依次移动分别表示以0 - nums.size() - 1为右端点的长度最小的数组(对子数组的分类!)
int i = 0, j = 0, sum = 0, res = INT32_MAX;
for(; j < nums.size(); j ++){
sum += nums[j];
if(sum < target) continue;
else{
while(i < j && sum - nums[i] >= target){
sum -= nums[i ++];
}
res = min(res, j - i + 1);
}
}
if(res == INT32_MAX) return 0;
else return res;
}
拓展题:
5.模拟过程
vector<vector<int>> generateMatrix(int n) {
int x = 0, y = 0;
// 模拟顺时针前进方向
int dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0}, d = 0;
vector<vector<int>> res(n, vector<int>(n, -1));
for(int i = 0; i < n * n; i ++ ){
res[x][y] = i + 1;
if(d == 0 && (y + 1 >= n || res[x][y + 1] != -1)) d = 1;
else if(d == 1 && (x + 1 >= n || res[x + 1][y] != -1)) d = 2;
else if(d == 2 && (y - 1 < 0 || res[x][y - 1] != -1)) d = 3;
else if(d == 3 && (x - 1 < 0 || res[x - 1][y] != -1)) d = 0;
x += dx[d];
y += dy[d];
}
return res;
}
6.前缀和与差分
本质为数列题,由通项公式求前n项和、由前n项和求通项公式
58. 区间和(第九期模拟笔试) (kamacoder.com)
int n;
cin >> n;
int a[n + 1], s[n + 1];
for(int i = 1; i <= n; i ++ ){
cin >> a[i];
s[i] = a[i] + s[i - 1];
}
int x, y;
while(cin >> x >> y){
cout << s[y + 1] - s[x] << endl;
}