基础算法
排序
sort库函数使用
左闭右开
vector<int>a;
a[n];
sort(a,a+n);
sort(a.begin(),a.end());
sort(a,a+n,greater<int>());
struct stu
{
string name;
int so;
bool operator<(const stu& t) const//重载操作符
{
return so<t.so;
}
bool operator > (const stu&t)const
{
return so>t.so;
}
}q[N];
bool cmp(stu a,stu b)//建立函数
{
return a.so<b.so;
}
sort(q,q+n,greater<stu>());//从大到小排序
sort(q,q+n,cmp);
//使原来的"相同"的值在序列中的相对位置不变**************************
stable_sort(q,q+n);
堆排序
用数组存,下标从1开始,heap[1]为根节点,对于结点heap[x],其左儿子heap[2*x],右儿子heap[2*x+1]
//涉及如下操作
/*
1.插入一个数 heap[++size]=x;up(size);
2.求集合当中的最小值 heap[1];
3.删除最小值 heap[1]=heap[size];size--;down(1);
4.删除任意一个元素 heap[k]=heap[size];size--;down(k);up(k);
5.修改任意一个元素 heap[k]=x;down(k);up(k);
*/
/*********初始化*********/
for (int i = 1; i <= n; i ++ ) scanf("%d", &h[i]);
for (int i = n / 2; i; i -- ) down(i);
/*********down*********/
void down(int u)
{
int t = u;
if (u * 2 <= n && h[u * 2] < h[t]) t = u * 2;//存在左儿子
if (u * 2 + 1 <= n && h[u * 2 + 1] < h[t]) t = u * 2 + 1;//存在右儿子
if (u != t)
{
swap(h[u], h[t]);
down(t);
}
}
/*********up*********/
void up(int u)
{
while (u / 2 && h[u] < h[u / 2])
{
heap_swap(u, u / 2);
u >>= 1;
}
}
/*********输出序列*********/
while (n -- )
{
printf("%d ", h[1]);
h[1] = h[n -- ];
down(1);
}
快速排序
void quick_sort(int*arr,int l ,int r)
{
if(l>=r)
return;
int p=arr[(l+r)/2];
int i=l-1,j=r+1;//哨兵
while(i<j)
{
do i++;while(arr[i]<p);
do j--;while(arr[j]>p);
if(i<j)
{
swap(arr[i],arr[j]);
}
}
quick_sort(arr,l,j);
quick_sort(arr,j+1,r);
}
归并排序
int arr[N];
int b[N];
void merge_sort(int*arr,int l,int r)
{
if(l>=r)
return;
int k=0;
int mid=(r+l)>>1;
merge_sort(arr,l,mid);
merge_sort(arr,mid+1,r);
int i=l,j=mid+1;
while(i<=mid&&j<=r)
{
if(arr[i]<arr[j])b[k++]=arr[i++];
else b[k++]=arr[j++];
}
while(i<=mid)b[k++]=arr[i++];
while(j<=r)b[k++]=arr[j++];
for(int i=l,k=0;i<=r;i++)
{
arr[i]=b[k++];
}
}
二分
int l=0,r=n-1;
int mid;
while(l<r)
{
mid=(l+r)>>1;
if(check())r=mid;
else l=mid+1;
}
while(l<r)
{
mid=(l+r+1)>>1;//当l=mid时,mid要定义为(l+r+1)>>1
if(check())l=mid;
else r=mid-1;
}
cout<<r;
前缀和
O(1)时间复杂度计算出几项的和
一维
for(int i=1;i<=n;i++)S[i]=S[i-1]+arr[i];
cout<<s[r]-s[l-1];//arr序列中第l个数到第r个数的和
二维
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
S[i][j]=S[i-1][j]+S[i][j-1]-S[i-1][j-1]+a[i][j];
}
}
cout<<S[x2][y2]-S[x2][y1-1]-S[x1-1][y2]+S[x1-1][y1-1];//二维序列子矩阵中所有数的和
前缀和求解字符串字串中字符出现次数
int s[26][N];
char str[N];
for (int i = 0; i < 26; i ++ )
for (int j = 1; str[j]; j ++ )
if (str[j] - 'a' == i)
s[i][j] = s[i][j - 1] + 1;
else
s[i][j] = s[i][j - 1];
s[i][b] - s[i][a - 1]//表示字母i在[a,b]区间内出现的次数
差分
O(1)时间复杂度给某几项加上常数C
//构造b数组:使得ai是bi的前缀和
for(int i=1;i<=n;i++)b[i]=a[i]-a[i-1];
b[l]+=c;//[l,r]区间每个数都加上c
b[r+1]-=c;
//利用b数组打印a数组
for(int i=1;i<=n;i++)printf("%d ",b[i]+=b[i-1]);
/*********优化版本*********/
//输入a1就相当于在[1,1]上插入一个a1,所以可以用这种方式初始化b[N]
void insert(int l,int r,int c)
{
b[l]+=c;
b[r+1]-=c;
}
insert(i,i,a[i]);//插入原始点
insert(l,r,c);//区间增加一个数
for(int i=1;i<=n;i++)printf("%d ",b[i]+=b[i-1]);//打印原序列
进制
字符串n转为r进制
int get(char c)
{
if (c <= '9') return c - '0';
return c - 'a' + 10;
}
LL calc(string n, LL r)
{
LL res = 0;
for (auto c : n)
{
if ((double)res * r + get(c) > 1e16) return 1e18;
res = res * r + get(c);//秦九韶算法
}
return res;
}
***
## 求解中位数
动态计算序列的中位数,需要两个堆,上面的堆始终与下面的堆相等或少一个元素,下面的堆存储中位数和比它小的数,上面的堆存储比它大的数
```C++
/*********初始化*********/
#include <set>
multiset<int> up,down;
void adjust()
{
while (up.size() > down.size())//上面堆容量过大,将上面堆的最小值插入到下面堆
{
down.insert(*up.begin());
up.erase(up.begin());
}
while (down.size() > up.size() + 1)//下面堆容量过大,将下面堆的最大值插入到上面堆中
{
auto it = down.end();//end返回的是最后一个元素的下一个位置
it -- ;//减一后才是最后的一个元素,即下面堆的最大值
up.insert(*it);//上面堆插入
down.erase(it);//下面堆删除
}
}
/*********插入*********/
for(int i=1;i<=n;i++)
{
if (up.empty() || x < *up.begin()) down.insert(x);//优先插入下面堆,或者当插入元素比上面堆的最小值还小时
else up.insert(x);
adjust();//调整上下两个堆的容量大小关系
}
/*********删除*********/
auto it = down.end();
it -- ;
if (x <= *it) down.erase(down.find(x));//删除元素小于下面堆的最大值,则元素在下面堆中
else up.erase(up.find(x));
/*********输出中位数*********/
auto it = down.end();//因为保证下面堆的大小和上面相等或比下面大一,所以下面堆的最大值为中位数
it -- ;
printf("%d\n", *it);