快速排序:给定一组数字,实现快速排序。
时间复杂度: O(nlogn)
n: 表示每次对n的数字进行排列; logn: 表示将分支将n个元素划分品骏需要logn次
#include <iostream>
using namespace std;
const int N = 100010;
int f[N];
int n;
void quick_sort(int q[], int l, int r)
{
int i = l-1, j=r+1, x = q[l+r>>1]; // 这里的+1 -1, 都是while循环中的后缀++ 补回来了。
if (l >= r) return ; /// 这里必须等于
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);
}
int main()
{
cin >> n;
for(int i=0; i<n; i++) cin >> f[i];
quick_sort(f, 0, n-1);
for(int i=0; i<n; i++) cout << f[i] << " ";
return 0;
}
快速排序相关例题: 直接查找第k个数字。和上面代码类似,就不给出了。
归并排序: 和快速排序有点类似,过程反了一下。
时间复杂度: O(nlogn)
#include <iostream>
using namespace std;
const int N = 100010;
int q[N], tmp[N];
int 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) ///< 双指针进行数组的排序, 每次将较小的数组中的元素放入tmp数组中
{
if(q[i] <= q[j] ) tmp[k++] = q[i++];
else tmp[k++] = q[j++];
}
while(i <= mid) tmp[k++] = q[i++]; ///< 扫尾工作, 如果一个数组已经完成元素进入tmp数组,另一个数组中还有元素,那么直接放入tmp数组中
while(j <= r) tmp[k++] = q[j++];
for(int i=l, j=0; i<=r;j++,i++) q[i] = tmp[j]; ///< 物归原主, 将tmp数组存放的两个排序数组的元素放到原数组中
}
int main()
{
cin >> n;
for(int i=0; i<n; i++) cin >> q[i];
merge_sort(q, 0, n-1);
for(int i=0; i<n; i++) cout << q[i] << " ";
return 0;
}
相关例题: 逆序对的数量
详情见代码部分讲解。
// 1. 逆序对的数量 = 逆序对两个数均在左边 + 逆序对两个数均在右边 + 逆序对两个数一左一右。
// 2. 我们只需要求 逆序对一左一右的情况即可, 剩下的进行递归求,即可得到所有种方案.
#include <iostream>
using namespace std;
const int N = 100010;
int q[N], tmp[N];
int n;
typedef long long LL;
LL merge_sort(int l, int r)
{
if(l>=r) return 0;
int mid = l + r >> 1 ;
LL re = merge_sort(l,mid) + merge_sort(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++];
re += 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 re;
}
int main()
{
cin >> n;
for(int i=0; i<n; i++) cin >> q[i];
cout << merge_sort(0, n -1);
return 0;
}
二分查找
1. 查找数的范围
给定一个按照升序排列的长度为n的整数数组,以及 q 个查询。
对于每个查询,返回一个元素k的起始位置和终止位置(位置从0开始计数)。
如果数组中不存在该元素,则返回“-1 -1”。
输入格式
第一行包含整数n和q,表示数组长度和询问个数。第二行包含n个整数(均在1~10000范围内),表示完整数组。
接下来q行,每行包含一个整数k,表示一个询问元素。
输出格式
共q行,每行包含两个整数,表示所求元素的起始位置和终止位置。
如果数组中不存在该元素,则返回“-1 -1”。
#include <iostream>
using namespace std;
const int N = 100010;
int n,m;
int q[N];
int main()
{
cin >> n >> m;
for(int i=0; i<n; i++) cin>> q[i];
while(m--)
{
int x;
cin >> x;
// 进行二分
int l = 0, r = n -1;
while(l < r)
{
int mid = l + r >> 1;
if(q[mid] >= x) r= mid; /// 满足某种性质, 是r=mid 就不用 + 1;
else l = mid + 1;
}
if( q[l] != x) cout << "-1 -1" << endl;
else{
cout << l << " ";
int l=0,r= n-1;
while(l < r)
{
int mid = l + r + 1>> 1; /// 满足某种性质, 是 l=mid 就需要 + 1;
if(q[mid] <= x) l = mid;
else r = mid - 1;
}
cout << l << endl;
}
}
return 0;
}
2. 三次方根
给定一个浮点数n,求它的三次方根。
输入格式
共一行,包含一个浮点数n。输出格式
共一行,包含一个浮点数,表示问题的解。注意,结果保留6位小数。
#include <iostream>
using namespace std;
int main()
{
double x;
cin >> x;
double l = -10000, r = 10000;
///< 保留几位小数, 这里就多2位, 如果是保留小数点后4位, r-l >1e-6 就行
while(r -l > 1e-8)
{
double mid = (l + r) / 2 ;
if(mid * mid * mid >= x) r = mid;
else l = mid;
}
//printf("%lf\n", l); ///< 这个是默认输出小数点后面6位的
printf("%.6f\n", l);
return 0;
}
实现高精度加法、减法、乘法、除法
加法: 两位数均是长度在【1,100000】.
减法: 同上。
乘法:一个数是长度在【1,100000】,另一个数范围是【0-1000】 注意一个是长度,一个是范围。
除法: 一个数是长度在【1,100000】,另一个数范围是【0-1000】
#include <iostream>
#include <vector>
using namespace std;
vector<int> add(vector<int>& A, vector<int>& B)
{
vector<int> C;
// t为进位
int t = 0;
for(int i=0; i < A.size() || i < B.size(); i++)
{
if(i <= A.size()) t += A[i];
if(i <= B.size()) t += B[i];
C.push_back(t % 10);
t /= 10;
}
if(t) C.push_back(1); ///< 如果高位有进位, 添加上1
return C;
}
int main()
{
string a,b;
cin >> a >> b;
vector<int> A, B;
for(int i=a.size()-1; i>=0; i--) A.push_back(a[i] - '0'); ///< 将个位放在数组前面
for(int i=b.size()-1; i>=0; i--) B.push_back(b[i] - '0');
auto C = add(A, B);
/// 将答案C 数组输出出来, 注意顺序
for(int i= C.size()-1; i>=0; i--) cout << C[i];
return 0;
}
#include <iostream>
#include <vector>
using namespace std;
/// 判断A 是否大于B
bool cmp(vector<int>&A, vector<int>& B)
{
if(A.size() != B.size()) return A.size() >= B.size();
for(int i=A.size()-1; i>=0; i--)
if(A[i] != B[i])
return A[i] >= B[i];
return true;
}
vector<int> sub(vector<int>& A, vector<int>& B)
{
vector<int> C;
int t = 0; /// 表示借位
for(int i=0; i<A.size(); i++) ///< 这里是个位相减,从0开始遍历
{
t = A[i] - t; ///< t表示借位
if(i < B.size()) t -=B[i]; ///< 表示B上i位有数的话,减去
// 这里代表两种状态 1. t>=0 表示A[i] >= B[i] 能够直接减去,
// 2. t<0 表示 不够减, 需要借位, 在下面将t = 1, 然后下一位减去
C.push_back((t + 10) % 10); /// 表示了两种情况
if(t < 0) t = 1; ///< t< 0 表示借位了
else
t = 0;
}
// 去掉前面的0, 条件(位数大于1, && 前面的数字是0)
while(C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
int main()
{
string a, b;
cin >> a >> b;
vector<int> A, B;
for(int i=a.size()-1; i>=0; i--) A.push_back(a[i] - '0');
for(int i=b.size()-1; i>=0; i--) B.push_back(b[i] - '0');
if(cmp(A,B))
{
auto C = sub(A, B);
for(int i=C.size()-1; i>=0; i--) cout << C[i] ;
}
else
{
cout << '-';
auto C = sub(B, A);
for(int i=C.size()-1; i>=0; i--) cout << C[i];
}
return 0;
}
#include <iostream>
#include <vector>
using namespace std;
vector<int> multi(vector<int>&A ,int b)
{
vector<int> C;
int t =0;
for(int i=0; i<A.size() || t; i++) // 需加上|| t 表示 乘以b后超过A了, 还可以计算
{
if(i< A.size()) t += A[i] * b;
C.push_back( t % 10);
t /= 10;
}
while(C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
int main()
{
string a;
int b;
cin >> a >> b;
vector<int> A;
for(int i=a.size()-1; i>=0; i--) A.push_back(a[i] - '0');
auto C = multi(A,b);
for(int i=C.size() -1; i>=0; i--) cout << C[i];
}