第一讲 基础算法
1.快速排序
AcWing 785. 快速排序
https://www.acwing.com/problem/content/787/
点击查看代码
#include <iostream>
using namespace std;
const int N = 100010;
int a[N],n;
void quick_sort(int a[],int l,int r){
if(l >= r) return;
int i = l-1,j = r+1, x = a[l + r >> 1];
// a[l, i] a[j,r] 区间内必成立
// ①当左边i找到比x大的元素,右边找不到比x小的元素, j-- j--直到 j < i, a[i] > x a[j] < x。 a[l,j] a[j+1,r] 是合理的
//② 当左边i找不到比x大的元素,i++ i++ 直到 i == j, a[i]==a[j] > x 然后 do j--; a[j] < x , swap(a[i],a[j]); a[i] < x, a[j] > x; a[l,j] a[j+1,r] 是合理的
//③ 当左边找到,右边也找到,那么合理
while(i < j){
do i++; while(a[i] < x);
do j--; while(a[j] > x);
if(i < j) swap(a[i],a[j]);
}
quick_sort(a,l,j);
quick_sort(a,j+1,r);
}
int main(){
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
quick_sort(a,1,n);
for(int i = 1; i <= n; i++) cout << a[i] << " ";
}
点击查看代码
#include <iostream>
#include <stdlib.h>
#include <cmath>
#include <algorithm>
using namespace std;
const int N = 100010;
int a[N];
int n;
void quick_sort(int a[],int l,int r){
if(l >= r) return;
swap(a[l],a[(l+r) >> 1]);
int pivot = a[l],i = l,j = r;
// 原先的写法: while(a[j] >= pivot && i < j) j--;
// 这样会忽略与支点相同的元素
// 数组的所有数字全都一样,那么 i == j == l; 外层while(i < j)直接结束了,陷入死循环
// while(a[j] > pivot && i < j) j--; 把支点相同的元素也进行操作
//
while(i < j){
while(a[j] > pivot && i < j) j--;
a[i] = a[j];
if(i < j) i++;
while(a[i] < pivot && i < j) i++;
a[j] = a[i];
if(i < j) j--;
}
a[i] = pivot;
quick_sort(a,l,i-1);
quick_sort(a,i+1,r);
}
int main(){
ios::sync_with_stdio(false); cin.tie(0);
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
quick_sort(a,1,n);
for(int i = 1; i <= n; i++) cout << a[i] << " ";
return 0;
}
AcWing 786. 第k个数
https://www.acwing.com/problem/content/788/
点击查看代码
#include <iostream>
using namespace std;
const int N = 100010;
int a[N];
int n,k;
int quick_sort(int a[],int l,int r,int k){
if(l == r) return a[l];
int i = l-1, j = r+1, x = a[l + r >> 1];
while(i < j){
do i++; while(a[i] < x);
do j--; while(a[j] > x);
if(i < j) swap(a[i],a[j]);
}
//快排不确定支点的最终位置
int t = j-l + 1;
if(t >= k) return quick_sort(a,l,j,k);
else return quick_sort(a,j+1,r,k-t);
}
int main(){
cin >> n >> k;
for(int i = 1; i <= n; i++) cin >> a[i];
cout << quick_sort(a,1,n,k) << endl;
return 0;
}
点击查看代码
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int a[N];
int n,k;
int quick_sort(int a[],int l,int r){
if(l == r) return a[l];
if(l < r){
int pivot = a[l],i = l,j = r;
while(i < j){
while(a[j] > pivot && i < j) j--;
a[i] = a[j];
if(i < j) i++;
while(a[i] < pivot && i < j) i++;
a[j] = a[i];
if(i < j) j--;
}
a[i] = pivot;
if(i == k) return a[i];
if(i > k) return quick_sort(a,l,i-1); // important
if(i < k) return quick_sort(a,i+1,r);
}
}
int main(){
cin >> n >> k;
for(int i = 1; i <= n; i++) cin >> a[i];
cout << quick_sort(a,1,n) << endl;
return 0;
}
2. 归并排序
AcWing 787. 归并排序
https://www.acwing.com/problem/content/789/
点击查看代码
#include <iostream>
using namespace std;
const int N = 100010;
int n;
int a[N];
void merge_sort(int a[],int l,int r){
if(l >= r) return;
int mid = (l+r) >> 1;
merge_sort(a,l,mid);
merge_sort(a,mid+1,r);
int i = l,j = mid+1;
int b[r-l+2],k = 0;
while(i <= mid && j <= r){
if(a[i] <= a[j]) b[k++] = a[i++];
else b[k++] = a[j++];
}
while(i <= mid) b[k++] = a[i++];
while(j <= r) b[k++] = a[j++];
for(int p = l,q = 0; p <= r; p++,q++){
a[p] = b[q];
}
}
int main(){
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
merge_sort(a,1,n);
for(int i = 1; i <= n; i++) cout << a[i] << " ";
return 0;
}
AcWing 788. 逆序对的数量
https://www.acwing.com/problem/content/790/
点击查看代码
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 100010;
int n;
int a[N];
LL res;
void merge_sort(int a[],int l,int r){
if(l >= r) return;
int mid = (l + r) >> 1;
merge_sort(a,l,mid);
merge_sort(a,mid+1,r);
int k = 0,i = l,j = mid+1;
int temp[r-l+2];
while(i <= mid && j <= r){
if(a[i] <= a[j]) temp[k++] = a[i++];
else {
temp[k++] = a[j++];
res += mid-i+1;
}
}
//扫尾
while(i <= mid) temp[k++] = a[i++];
while(j <= r) temp[k++] = a[j++];
//物归原主
for(int p = l,q = 0; p <= r; p++,q++){
a[p] = temp[q];
}
}
int main(){
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
merge_sort(a,1,n);
cout << res << endl;
return 0;
}
3.二分
binary_search
点击查看代码
必须是 l <= r,
不然 a1,a2 mid = a1下标, a1可以找到 a2会找不到
int binary_search(int a[],int l,int r,int target){
while(l <= r){
int mid = l + (r-l)/2;
if(a[mid] == target) return mid;
if(a[mid] < target) l = mid + 1;
else r = mid - 1;
}
return -1;
}
lower_bound
即 lower_bound:如果数组中存在和target相等的数,那么结果就是相等最左边的数,否则返回 > target最小的数的下标
点击查看代码
// 返回的范围 [0,a.length]
// a[l] > target, 当target最小,l == r会死循环
// a[l] == target, 找到了,跳出来
int l_b(int a[],int l,int r,int target){
while(l <= r){
int mid = l + (r-l)/2;
if(l == r && a[l] >= target) break;
if(a[mid] < target) l = mid + 1;
else r = mid; //等于时取最左边
}
return l;
}
upper_bound
即 upper_bound:> target 的最小的那个数的下标
点击查看代码
int u_b(int a[],int l,int r,int target){
while(l <= r){
int mid = l + (r-l)/2;
if(l == r && a[mid] > target) break;
if(a[mid] <= target) l = mid + 1;
else r = mid;
}
return l;
}
AcWing 789. 数的范围
https://www.acwing.com/problem/content/791/
点击查看代码
#include <iostream>
using namespace std;
const int N = 100010;
int a[N];
int n,q,k;
int l_b(int target){
int l = 0, r = n-1;
while(l <= r){
int mid = l + (r-l)/2;
if(l == r && a[mid] >= target) break;
if(a[mid] < target) l = mid + 1;
else r = mid;
}
return l;
}
int u_b(int target){
int l = 0, r = n-1;
while(l <= r){
int mid = l + (r-l)/2;
if(l == r && a[mid] > target) break;
if(a[mid] <= target) l = mid + 1;
else r = mid;
}
return l;
}
int main(){
cin >> n >> q;
for(int i = 0; i < n; i++) cin >> a[i];
while(q--){
int k; cin >> k;
int t1 = l_b(k), t2 = u_b(k) - 1;
if(a[t1] != k) cout << -1 << " ";
else cout << t1 << " ";
if(t2 >= 0 && t2 < n && a[t2] == k) cout << t2 << endl;
else cout << -1 << endl;
}
}
790. 数的三次方根
https://www.acwing.com/problem/content/description/792/
点击查看代码
在[-100,100]上二分一个数,使 r-l 的范围(精度) < 0.0000001
然后根据题中条件去缩小 l,r的范围
#include <iostream>
#include <cstdio>
using namespace std;
int main(){
double n; cin >> n;
double l = -100,r = 100;
while(r-l > 0.0000001){
double mid = l + (r-l)/2;
if(mid * mid * mid < n) l = mid;
else r = mid;
}
printf("%.6lf",l);
}
4.高精度
AcWing 791. 高精度加法
https://www.acwing.com/problem/content/793/
点击查看代码
#include <iostream>
#include <vector>
using namespace std;
vector<int> va,vb,vc;
int main(){
string sa,sb; cin >> sa >> sb;
for(int i = sa.length()-1; i >= 0; i--) va.push_back(sa[i]-'0');
for(int i = sb.length()-1; i >= 0; i--) vb.push_back(sb[i]-'0');
long unsigned int i = 0, j = 0,t = 0;
while(i <= va.size()-1 || j <= vb.size()-1){
if(i <= va.size()-1) t += va[i++];
if(j <= vb.size()-1) t += vb[j++];
vc.push_back(t%10);
t /= 10;
}
if(t != 0) vc.push_back(t);
for(int i = vc.size()-1; i >= 0; i--) cout << vc[i];
}
AcWing 792. 高精度减法
https://www.acwing.com/problem/content/794/
点击查看代码
#include <iostream>
#include <vector>
using namespace std;
int cmp(vector<int> va,vector<int> vb){
if(va.size() != vb.size()) return va.size() > vb.size();
for(int i = va.size()-1; i >= 0; i--){
if(va[i] == vb[i]) continue;
return va[i] > vb[i];
}
}
int main(){
string sa,sb; cin >> sa >> sb;
vector<int> va,vb,vc;
for(int i = sa.length()-1; i >= 0; i--) va.push_back(sa[i] - '0');
for(int i = sb.length()-1; i >= 0; i--) vb.push_back(sb[i] - '0');
if(cmp(va,vb)){
int t = 0; //借位
for(int i = 0; i <= va.size()-1; i++){
va[i] += t;
if(i <= vb.size()-1) va[i] -= vb[i];
vc.push_back((va[i] + 10) % 10);
if(va[i] < 0) t = -1;
else t = 0; // important, 不然 不该借位的时候也借位了
}
}else{
cout << "-";
int t = 0;
for(int i = 0; i <= vb.size()-1; i++){
vb[i] += t;
if(i <= va.size()-1) vb[i] -= va[i];
vc.push_back((vb[i] + 10) % 10);
if(vb[i] < 0) t = -1;
else t = 0;
}
}
//去掉前置0(高位0),000->00
while(vc.size() > 1 && vc.back() == 0) vc.pop_back();
for(int i = vc.size()-1; i >= 0; i--) cout << vc[i];
return 0;
}
AcWing 792. 高精度减法
https://www.acwing.com/problem/content/description/795/
点击查看代码
#include <iostream>
#include <vector>
using namespace std;
int main(){
string sa,sb; cin >> sa >> sb;
vector<int> va,vb;
for(int i = sa.length()-1; i >= 0; i--) va.push_back(sa[i]-'0');
for(int i = sb.length()-1; i >= 0; i--) vb.push_back(sb[i]-'0');
vector<int> vc(va.size() + vb.size() + 11,0);
// va * vb , 用vb的个位乘以va的每一位
for(int i = 0; i < vb.size(); i++){
for(int j = 0; j < va.size(); j++){
int t = vc[i+j] + vb[i] * va[j];
vc[i+j] = t % 10;
vc[i+j+1] += t / 10;
}
}
//去前置0
while(vc.size() > 1 && vc.back() == 0) vc.pop_back();
for(int i = vc.size()-1; i >= 0; i--) cout << vc[i];
return 0;
}
AcWing 794. 高精度除法
https://www.acwing.com/problem/content/796/
一个大数除以一个小数
让这个小数转为int
大数从高位开始除, x为余数
点击查看代码
#include <iostream>
#include <vector>
#include <deque>
using namespace std;
/**
* 88
* 2
**/
int x = 0; //余数
deque<int> div(vector<int>& a,int b){
//a是被除数,b是除数
deque<int> c(a.size()); //商集合
for(int i = 0; i < a.size(); i++){
c[i] = (x*10 + a[i]) / b;
x = (x*10 + a[i]) % b;
}
while(c.size() > 1 && c.front() == 0) c.pop_front(); //注意清除的是前置0
return c;
}
int main(){
// s1 >= s2
string s1,s2; cin >> s1 >> s2;
vector<int>a;
for(int i = 0; i < s1.length(); i++) a.push_back(s1[i]-'0');
int b = 0;
for(int i = 0; i < s2.length(); i++){
b = b*10;
b += s2[i]-'0';
}
deque<int> c = div(a,b);
for(int i = 0; i < c.size(); i++) cout << c[i];
cout << endl << x << endl;
return 0;
}
5.前缀和与差分
AcWing 795. 前缀和
https://www.acwing.com/problem/content/797/
点击查看代码
#include <iostream>
using namespace std;
const int N = 100010;
int a[N],b[N];
int n,m;
int l,r;
int main(){
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++) b[i] += a[i] + b[i-1];
while(m--){
cin >> l >> r;
cout << b[r] - b[l-1]<< endl;
}
return 0;
}
AcWing 796. 子矩阵的和
https://www.acwing.com/problem/content/798/
点击查看代码
#include <iostream>
using namespace std;
const int N = 1000 + 11;
int a[N][N],b[N][N];
int n,m,q;
int x1,y1,x2,y2;
int main(){
cin >> n >> m >> q;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
cin >> a[i][j];
}
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
b[i][j] = a[i][j] + b[i-1][j] + b[i][j-1] - b[i-1][j-1];
}
}
while(q--){
cin >> x1 >> y1 >> x2 >> y2;
cout << b[x2][y2] - b[x1-1][y2] -b[x2][y1-1]+ b[x1-1][y1-1] << endl;
}
return 0;
}
AcWing 797. 差分
a数组的每一个数都是 b数组从0开始的前缀和
https://www.acwing.com/solution/content/26588/
点击查看代码
#include <iostream>
using namespace std;
const int N = 100010;
int a[N],b[N];
int n,m,l,r,c;
int main(){
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++) b[i] = a[i] - a[i-1];
while(m--){
cin >> l >> r >> c;
b[l] += c;
b[r+1] -= c;
}
int t = 0;
for(int i = 1; i <= n; i++){
t += b[i];
cout << t << " ";
}
return 0;
}
AcWing 798. 差分矩阵
6.双指针算法
AcWing 799. 最长连续不重复子序列
https://www.acwing.com/problem/content/801/
点击查看代码
#include <iostream>
using namespace std;
const int N = 100010;
int q[N],s[N];
int n;
int main(){
cin >> n;
for(int i = 1; i <= n; i++) cin >> q[i];
int res = 0;
for(int i = 1,j = 1; i <= n; i++){
s[q[i]]++;
// 在[j,i]区间内都要防止有重复的元素
while(j < i && s[q[i]] > 1) s[q[j++]]--;
res = max(res,i-j+1);
}
cout << res << endl;
return 0;
}
点击查看代码 - unordered_map
#include <iostream>
#include <unordered_map>
using namespace std;
const int N = 100010;
int q[N];
int n;
unordered_map<int,int> ump;
int main(){
cin >> n;
for(int i = 1; i <= n; i++) cin >> q[i];
int res = 0;
for(int i = 1,j = 1; i <= n; i++){
ump[q[i]]++;
// 在[j,i]区间内都要防止有重复的元素
while(j < i && ump[q[i]] > 1) ump[q[j++]]--;
res = max(res,i-j+1);
}
cout << res << endl;
return 0;
}
AcWing 800. 数组元素的目标和(two_sum)
https://www.acwing.com/problem/content/802/
点击查看代码
#include <iostream>
using namespace std;
const int N = 100010;
int a[N],b[N];
int n,m,x;
int main(){
cin >> n >> m >> x;
for(int i = 0; i < n; i++) cin >> a[i];
for(int i = 0; i < m; i++) cin >> b[i];
for(int i = 0,j = m-1; i < n; i++){
while(j > 0 && b[j] + a[i] > x) j--;
if(b[j] + a[i] == x){
cout << i << " " << j << endl;
break;
}
}
return 0;
}
点击查看代码_unordered_map查找
#include <iostream>
#include <unordered_map>
using namespace std;
const int N = 100010;
int a[N];
unordered_map<int,int> mp;
int main(){
int n,m,x; scanf("%d%d%d",&n,&m,&x);
for(int i = 1; i <= n; i++) scanf("%d",&a[i]);
for(int i = 1; i <= m; i++){
int t; scanf("%d",&t);
mp[t] = i;
}
for(int i = 1; i <= n; i++){
if(mp.count(x-a[i])){
printf("%d %d\n",i-1,mp[x-a[i]]-1);
break;
}
}
return 0;
}
AcWing 2816. 判断子序列
https://www.acwing.com/problem/content/803/
点击查看代码
#include <iostream>
using namespace std;
const int N = 100010;
int n,m;
int a[N],b[N];
int main(){
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= m; i++) cin >> b[i];
bool isok = false;
for(int i = 1, j = 1; i <= n; i++){
while(j < m && a[i] != b[j]) j++;
if(i == n && j <= m && a[i] == b[j]){ // 防止越界
isok = true;
break;
}
j++;
}
if(isok) cout << "Yes" << endl;
else cout << "No" << endl;
return 0;
}
点击查看代码-y总
#include <iostream>
#include <cstring>
using namespace std;
const int N = 100010;
int n, m;
int a[N], b[N];
int main()
{
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
for (int i = 0; i < m; i ++ ) scanf("%d", &b[i]);
int i = 0, j = 0;
while (i < n && j < m)
{
if (a[i] == b[j]) i ++ ;
j ++ ;
}
if (i == n) puts("Yes");
else puts("No");
return 0;
}
7.位运算
AcWing 801. 二进制中1的个数
点击查看代码
#include <iostream>
using namespace std;
const int N = 100010;
int a[N];
int main(){
int n; cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++){
int res = 0;
for(int k = 31; k >= 0; k--) res += (a[i] >> k & 1);
cout << res << " ";
}
return 0;
}
点击查看代码
#include <iostream>
using namespace std;
const int N = 100010;
int a[N];
int lowbit(int x){
return x&(-x);
}
int main(){
int n; cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++){
int res = 0;
while(a[i]) a[i] -= lowbit(a[i]), res++;
cout << res << " ";
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律