acwing算法基础课第一讲基础算法复习总结

1.快速排序:

快速排序:

主要思想--基于分治

1.确定分界点x,常用:左边界q[l],右边界q[r],中间q[(l+r)/2]

2.根据x的值把区间分为左右两半,使得左边区间所有的数都小于等于x,右边所有数都大于等于x

3.递归处理左右两段

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010;
int a[N];

void quick_sort(int a[],int l,int r)
{
    if(l>=r) return;
    int x=a[(l+r)/2];//随便取a[]中的一个数
    
    int i=l-1,j=r+1;
    while(i<j)
    {
        while(a[++i]<x);
        while(a[--j]>x);
        if(i<j) swap(a[i],a[j]);
    }
    quick_sort(a,l,j);
    quick_sort(a,j+1,r);
}
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++) cin>>a[i];
    quick_sort(a,0,n-1);
    for(int i=0;i<n;i++) cout<<a[i]<<" ";
    return 0;
}#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010;
int a[N];

void quick_sort(int a[],int l,int r)
{
    if(l>=r) return;
    int x=a[(l+r)/2];//随便取a[]中的一个数
    
    int i=l-1,j=r+1;
    while(i<j)
    {
        while(a[++i]<x);
        while(a[--j]>x);
        if(i<j) swap(a[i],a[j]);
    }
    quick_sort(a,l,j);
    quick_sort(a,j+1,r);
}
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++) cin>>a[i];
    quick_sort(a,0,n-1);
    for(int i=0;i<n;i++) cout<<a[i]<<" ";
    return 0;
}

第k个数:

根据快排的思想:

分别统计左边右边各有多少个数

1.k<=sl(左半区间数的个数),那么第k小的数一定<=x,只递归左边即可

2.k>sl(k大于左半边个数),说明第k小的数>=x,只递归右半边即可,此时第k小的数

在右半边就是第k-sl小的数,因为去掉了sl个更小的

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010;
int n,k;
int a[N];
int quick_sort(int a[],int l,int r,int k)
{
    if(l>=r) return a[l];
    int x=a[(l+r)/2];
    int i=l-1,j=r+1;
    while(i<j)
    {
        while(a[++i]<x);
        while(a[--j]>x);
        if(i<j) swap(a[i],a[j]);
    }
    if(j-l+1>=k) return quick_sort(a,l,j,k);//如果j停下来的位置距离起点超过了k个数
    else return quick_sort(a,j+1,r,k-(j-l+1));
}
int main()
{
    cin>>n>>k;
    for(int i=0;i<n;i++) cin>>a[i];
    cout<<quick_sort(a,0,n-1,k);
    return 0;
}

2.归并排序

归并排序:

1.确定分界点

2.递归排序left,right

3.归并两个有序序列,合二为一(双指针算法)

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010;
int a[N];
int n;
void merge_sort(int a[],int l,int r)
{
    if(l>=r) return;
    int tmp[N];
    int mid=(l+r)/2;
    merge_sort(a,l,mid),merge_sort(a,mid+1,r);
    
    int i=l,j=mid+1;
    int k=0;
    while(i<=mid && j<=r)
    {
        if(a[i]<a[j]) tmp[k++]=a[i++];
        else tmp[k++]=a[j++];
    }
    while(i<=mid) tmp[k++]=a[i++];
    while(j<=r) tmp[k++]=a[j++];
    
    for(int i=0,j=l;i<k;i++,j++)
    {
        a[j]=tmp[i];
    }
}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++) cin>>a[i];
    merge_sort(a,0,n-1);
    for(int i=0;i<n;i++) cout<<a[i]<<" ";
    return 0;
}

逆序对的数量:

在归并排序归并两个有序序列的过程中,逆序对有三种情况:

1.只看左半区间内的逆序对

2.只看右半区间内的逆序对

3.横跨左右区间的逆序对

假设我们的归并排序函数能够返回区间内的逆序对数量

则1.merge_sort(l,mid); 2.merge_sort(mid+1,r)

3.在归并的过程中如果左半区间某个数x比右半区间某个数y大,那么从左半区间从该数x开始,到最后一个数结束,都与右半区间这个数y是逆序对,所以我们一旦遇到a[i]>a[j],最终结果res就要+=

mid-i+1

本质上来说,通过分治和递归,最深层的单个元素return返回上层,就是两个元素,这两个元素是来自两个左右两个区间的的,也就是3的情况。本质上,1,2单独的情况是不存在的。

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010;
int a[N],tmp[N];
int n;
typedef long long LL;

LL merge_sort(int a[],int l,int r)
{
    if(l>=r) return 0;
    
    int mid=(l+r)/2;
    LL res=merge_sort(a,l,mid)+merge_sort(a,mid+1,r);
    
    int i=l,j=mid+1;
    int k=0;
    while(i<=mid&&j<=r)
    {
        if(a[i]<=a[j]) tmp[k++]=a[i++];
        else
        {
            tmp[k++]=a[j++];
            res+=mid-i+1;
        }
    }
    while(i<=mid) tmp[k++]=a[i++];
    while(j<=r) tmp[k++]=a[j++];
    
    for(int i=0,j=l;i<k;i++,j++)
    {
        a[j]=tmp[i];
    }
    return res;
}

int main()
{
    cin>>n;
    for(int i=0;i<n;i++) cin>>a[i];
    cout<<merge_sort(a,0,n-1)<<endl;
    return 0;
}

二分:

1.数的范围:

二分的本质是二段性不是单调性。

2.数的三次方根: 

高精度:

高精度加法:

基础算法,用字符串存储

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
string a,b;
vector<int> add(vector<int>& A,vector<int>& B)
{
    vector<int> C(max(A.size(),B.size())+10,0);
    for(int i=0;i<A.size();i++) C[i]+=A[i];
    for(int i=0;i<B.size();i++) C[i]+=B[i];
    
    for(int i=0;i<C.size();i++)
    {
        C[i+1]+=C[i]/10;
        C[i]%=10;
    }
    
    while(C.back()==0 && C.size()>1) C.pop_back();
    reverse(C.begin(),C.end());
    return C;
}
int main()
{
    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');
    
    vector<int> C=add(A,B);
    
    for(int i=0;i<C.size();i++) cout<<C[i];
    return 0;
}

高精度减法:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
string a,b;
bool cmp(vector<int> &A,vector<int> &B)
{
    if(A.size()!=B.size()) return A.size()>B.size();
    else
    {
        for(int i=A.size()-1;i>=0;i--)//从最高位开始比较,由于A,B是倒着存数组的,所以倒着按高位到地位的顺序比较
        {
            if(A[i]!=B[i]) return A[i]>B[i];
        }
        //如果算到最后A和B相同,返回true,因为我们是要求A>=B即可
        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++)//已知A的size>=B的size
    {
        t=A[i]-t;//去掉上一轮的进位
        if(i<B.size()) t-=B[i];//如果B[i]存在,就减去B[i]
        
        C.push_back((t+10)%10);//保证t>0
        if(t<0) t=1;//t<0说明进位为1
        else t=0;
    }
    while(C.back()==0&&C.size()>1) C.pop_back();
    reverse(C.begin(),C.end());
    return C;
}
int main()
{
    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');
    vector<int> C;
    if(cmp(A,B))
    {
        C=sub(A,B);
        for(int i=0;i<C.size();i++) cout<<C[i];
    }
    else
    {
        C=sub(B,A);
        cout<<"-";
        for(int i=0;i<C.size();i++) cout<<C[i];
    }
    return 0;
}

高精度乘法

1.高精度*低精度

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
string a;
int b;
vector<int> mul(vector<int> A,int b)
{
    vector<int> C(A.size()+10,0);
    for(int i=0;i<A.size();i++)
    {
        C[i]=A[i]*b;
    }
    for(int i=0;i<C.size();i++)
    {
        C[i+1]+=C[i]/10;
        C[i]%=10;
    }
    while(C.back()==0&&C.size()>1) C.pop_back();
    reverse(C.begin(),C.end());
    return C;
}

int main()
{
    cin>>a>>b;
    vector<int> A;
    for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');
    
    vector<int> C=mul(A,b);
    for(int i=0;i<C.size();i++) cout<<C[i];
    return 0;
}

2.高精度*高精度

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
string a,b;

vector<int> mul(vector<int> &A,vector<int> &B)
{
    vector<int> C(A.size()+B.size(),0);
    for(int i=0;i<A.size();i++)
    {
        for(int j=0;j<B.size();j++)
        {
            C[i+j]+=A[i]*B[j];
        }
    }
    for(int i=0;i<C.size();i++)
    {
        C[i+1]+=C[i]/10;
        C[i]%=10;
    }
    while(C.back()==0&&C.size()>1) C.pop_back();
    reverse(C.begin(),C.end());
    return C;
}
int main()
{
    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');
    
    vector<int> C=mul(A,B);
    
    for(int i=0;i<C.size();i++) cout<<C[i];
    return 0;
}

高精度除法(高精度除以低精度) 

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
vector<int> div(vector<int> &A,int b,int &r)
{
    vector<int> C;
    r=0;
    for(int i=A.size()-1;i>=0;i--)//与加减不同,除法从最高位开始算
    {
        r=r*10+A[i];
        C.push_back(r/b);
        r%=b;
    }
    //得到的C也是最高位在前的
    reverse(C.begin(),C.end());//这样得到的C就是低位在前
    while(C.back()==0&&C.size()>1) C.pop_back();//将高位前的0去掉
    reverse(C.begin(),C.end());//得到高位在前的正序数
    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');
    int r;//存余数
    vector<int> C=div(A,b,r);
    for(int i=0;i<C.size();i++) cout<<C[i];
    cout<<endl<<r;
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值