《算法笔记》——基础算法

基础算法

排序

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);

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值