第一章 基础算法

排序

快排
void quick_sort(int q[], int l, int r){
    if(l>=r) return; //只有一个数据 或者递归返回条件
    int x = q[l] , i = l-1, j = 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);
}

// 寻找第k小的数字
int quick_sort(int l, int r, int k){
    if(l==r) return q[l];

    int x = q[l] , i=l-1, j=r+1;
    while(i<j){
        do i++; while(q[i]<x);
        do j--; while(q[i]>x);
        if(i<j) swap(q[i], q[j]);
    }
    int s1 = j-l+1;
    if(k <= s1) return quick_sort(l, j, k);
    return quick_sort(j+1, r, k - s1);
}
归并排序
int tmp[N];
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 i = l, j = mid + 1, k = 0; 
	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++];
	
	// 注意i的范围是 [l, r] , r是包含的 
	for(int i = l, j = 0; i <= r; i++,j++) q[i] = tmp[j];
}

// 求逆序对个数
LL merge_sort(int l, int r){
	if(l>=r) return 0;
	
	int mid = l + r >> 1;	
	LL res = merge_sort(l, mid) + merge_sort(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++];
			res += mid - i + 1;
		}
	}
	while(i<=mid) tmp[k++] = q[i++];
	while(j<=r) tmp[k++] = q[j++];
	
	for(int i=l,j=0; i<=r; i++,j++) q[i] = tmp[j];
	return res;
}
堆排序
/*
    规则:小根堆(顶点是小于左右两个子节点)
    插入一个数 heap[++size] = x; up(size)
    求集合中的最小值 heap[1]
    删除最小值  heap[1] = heap[size--] down(1)
    删除任意一个元素 heap[k] = heap[size--] 值变小,往上走;值变大,往下走 down(k),up(k);
    修改任意一个元素 heap[k] = x ; down(k),up(k);

    输入一个长度为n的整数数列,从小到大输出前m小的数。 大根堆:升序
*/
int h[N],size;
void down(int u){
    int t = u;
    if(u * 2 <= size && h[u * 2] < h[t]) t = u * 2;
    if(u * 2 + 1 <= size && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
    if(u != t){ // 非叶子节点
        swap(h[u], h[t]);
        down(t);
    }
}
for(int i = 1; i <= n; i++) cin>>h[i];
size = n;
// 构建大根堆:从下往上构建,而且是从非叶子节点开始
for(int i = n/2; i; i--) down(i);

while(m--){
   cout << h[1];
    // 删除根节点,并更新堆
    h[1] = h[size--];
    down(1);
}
二分 (一个应用求三次开根)
// 右边部分
int l = 0, r = n-1;
while(l < r){
    int mid = l + r >> 1;
    if(q[mid] >= x) r = mid;
    else l = mid + 1;
}
// 左边部分
while(l < r){
	int mid = l + r + 1 >> 1;
    if(q[mid] <= x) l = mid;
    else r = mid - 1;
 }
前缀和
for(int i = 1; i <= n; i++) s[i] = s[i-1] + a[i];

// 二维
for(int i = 1;i <= n; i++)
    for(int j = 1;i <= m; j++)
        s[i][j] = s[i][j-1] + s[i-1][j] - s[i-1][j-1] + a[i][j]; // 求前缀和 
printf("%d\n", s[x2][y2] - s[x2][y1] - s[x1][y2] + s[x1][y1] - 1);  // 算子矩阵的和
差分
void insert(int l, int r, int c){
    b[l] += c;  // 拉高起点
    b[r+1] -= c;    // 距离拉大
}

for(int i = 1; i <= n; i++)  insert(i, i, a[i]);
while(m--){
    int l, r, c;
    scanf("%d%d%d", &l,&r,&c);
    insert(l,r,c);
}
for(int i = 1; i <= n; i++) b[i] += b[i-1];	// 前边只要有一个数字加了,那么就会影响后边

// 二维差分矩阵
void insert(int x1, int y1, int x2, int y2, int c){
    b[x1][y1] += c;
    b[x2+1][y2+1] += c;
    b[x1][y2+1] -= c;
    b[x2+1][y1] -= c;
}
insert(i, j, i, j, a[i][j]);
insert(x1,y1,x2,y2,c);
for(int i = 1; i <= n; i++)
   for(int j = 1;j <= m; j++)
        b[i][j] = b[i-1][j] + b[i][j-1] - b[i-1][j-1] + b[i][j];	// 前缀和

双指针

同向双指针,异向双指针,快慢指针,距离为k的指针

/*
给定两个升序排序的有序数组A和B,以及一个目标值x。数组下标从0开始。
请你求出满足A[i] + B[j] = x的数对(i, j)。
*/
for(int i=0; i<n; i++){
  while(j >= 0 && a[i] + b[j] > x) j--;
  if(a[i] + b[j] == x) printf("%d %d\n", i, j);

    // a[i]+b[j] < x 则i继续移动,所以就不再需要写代码
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值