1. 算法基础整合
2022/7/15 14:20:28
本文主要是介绍1. 算法基础整合,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
1. 基础算法
1.1 排序
1.1.1 快速排序
模板:Acwing785 快速排序
题目:将一个长度为 \(n\) 的数组 \(q\) 从小到大排序。
思路:
-
选取界点 \(x\),一般为 \(q_{(l+r)/2}\)(\(l,r\) 为排序的左端点和右端点) 或随机选点(效率较高)。
-
将 \(\le x\) 的数换到左边,将 \(\ge x\) 的数换到右边(主要步骤)。
-
递归处理 \(x\) 的左右两边。
最好情况 | 平均情况 | 最坏情况 |
---|---|---|
$$O(n\log n)$$ | \(O(n\log n)\) | \(O\left(n^2\right)\) |
代码:
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int N = 1e5+10; int q[N]; void qsort(int q[], int l, int r) { if (l >= r) //递归边界 return ; int i = l-1, j = r+1, x = q[(l+r)/2]; //第1步 while (i < j) { //第2步 do i++; while (q[i] < x); do j--; while (q[j] > x); if (i < j) swap(q[i], q[j]); } qsort(q, l, j), qsort(q, j+1, r); //第3步 } int main() { int n; scanf("%d", &n); for (int i = 1; i <= n; ++i) scanf("%d", &q[i]); qsort(q, 1, n); for (int i = 1; i <= n; ++i) printf("%d ", q[i]); return 0; }
1.1.2 归并排序
模板:Acwing 787. 归并排序
题目:将一个长度为 \(n\) 的数组 \(q\) 从小到大排序。
思路:
-
确定分界点 \(x=\dfrac{l+r}{2}\).
-
递归排序 \(x\) 的左右两边。
-
将排好序的两边合并(主要步骤)。
最好情况 | 平均情况 | 最坏情况 |
---|---|---|
\(O(n\log n)\) | \(O(n\log n)\) | \(O(n\log n)\) |
代码:
#include <iostream> #include <algorithm> #include <cstdio> using namespace std; const int N = 1e5+10; int q[N], tmp[N]; void msort(int q[], int l, int r) { if (l >= r) //递归边界 return ; int mid = l + r >> 1; //步骤1 msort(q, l, mid), msort(q, mid+1, r); //步骤二 int i = l, j = mid+1, k = 1; //步骤三 while (i <= mid && j <= r) tmp[k ++] = (q[i] < q[j]) ? q[i ++] : q[j ++]; while (i <= mid) tmp[k ++] = q[i ++]; while (j <= r) tmp[k ++] = q[j ++]; for (int i = l, j = 1; i <= r; ++i, ++j) q[i] = tmp[j]; } int main() { int n; scanf("%d", &n); for (int i = 1; i <= n; ++i) scanf("%d", &q[i]); msort(q, 1, n); for (int i = 1; i <= n; ++i) printf("%d ", q[i]); return 0; }
应用:Acwing788. 逆序对的数量
题目:计算一个长度为 \(n\) 的序列 \(q\) 中逆序对的数量(逆序对的定义:若 \(i<j\) 且 \(q_i>q_j\),则 \((i,j)\) 即为一个逆序对)。
思路:运用归并排序。
设 \(m(l, r)\) 表示 \(q_l\sim q_r\) 中的逆序对数量, \(x=\dfrac{l+r}{2}\). 则 \(m(l,r)=m(l,x)+m(x+1,r)\)\(+\) 横跨两段的逆序对的数量。
\(m(l,x)\) 和 \(m(x+1,r)\) 可以通过递归求出。那么横跨两段的逆序对的数量可以在归并排序的过程中完成。
看看归并排序的核心部分:
int i = l, j = mid+1, k = 1; //这里的mid即上文中的x 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 ++];
再结合逆序对的定义,可知当 \(q_i>q_j\) 时,\((i,j),(i+1,j),...,(x,j)\) 均为逆序对(因为 \(q_l\sim q_x\) 已经排好序了,所以 \(q_x\ge q_{x-1}\ge ...\ge q_i>q_j\))。而 \(i\sim x\) 共有 \(x-i+1\) 个数。所以当 \(q_i\ge q_j\) 时,横跨两段的逆序对数量就增加 \(x-i+1\).
代码:
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; #define int long long //注意此题要开long long,仔细都数据范围 const int N = 1e5+10; int q[N], tmp[N]; int msort(int q[], int l, int r) { if (l >= r) return 0; //注意,由于函数返回类型变为了int,所以不能直接return,要加上返回值0 int mid = l + r >> 1; int ans = msort(q, l, mid) + msort(q, mid+1, r); int i = l, j = mid+1, k = 1; while (i <= mid && j <= r) { if (q[i] <= q[j]) tmp[k ++] = q[i ++]; else tmp[k ++] = q[j ++], ans += mid-i+1; } while (i <= mid) tmp[k ++] = q[i ++]; while (j <= r) tmp[k ++] = q[j ++]; for (int i = l, j = 1; i <= r; ++i, ++j) q[i] = tmp[j]; return ans; } signed main() { int n; scanf("%lld", &n); for (int i = 1; i <= n; ++i) scanf("%lld", &q[i]); int ans = msort(q, 1, n); printf("%lld\n", ans); return 0; }
1.2 二分
1.2.1 整数二分
1.2.2 小数二分
这篇关于1. 算法基础整合的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南