第一周算法复习

# 第一周算法复习(2021/11/08-2021/11/14)

快排

虽然在c++中有内置的sort函数帮助我们进行时间复杂度为nlogn的快速排序,不过快排的思想和双指针算法还是很值得我们学习的

快排的思想:

  • 选一个分界点,可以是q[]的任何一个数,q[l],q[r],q[l+r>>1]都可以,一般是用q[l+r>>1]

  • 以分界点的值为界,把所有小于等于分界点的数都移动到分界点左边,把所有大于等于分界点的数都移动到分界点右边

  • 不断递归

很显然,快排的关键就在于我们怎么以分界点为界,移动值到分界点的两边。

  1. 开另外两个数组a[],b[],把所有小于等于分界点的数都输入到a[]中,大于等于分界点的数都输入到b[]中,然后再赋值给q[],这样虽然要多扫描一遍q[]和额外开了两个数组,不过无伤大雅

  2. 利用双指针算法能够进行优雅地处理,首先将两个指针放在q[]的最左端和最右端,因为每次都要先移动指针再判断情况,当左侧指针遇到一个不小于分界点的数那么就停止,当右侧指针遇到一个不大于分界点的数,也停止,两个指针都停止之后,交换值继续往前走

板子:

 void quick_sort(int q[],int l,int r){
    if (l>=r) return ;
    int i=l-1,j=r+1,x=q[l+r>>1];
    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);
 }

sort

用法:

 const int N=1e6+10;
 int q[N];
 sort(q,q+N);
 //将整个q数组按从小到大排列

归并

归并的思想:

  • 也是分支和双指针

  • 时间复杂度也为nlogn

  • 它先进行递归,再进行处理

  • 这是一个稳定排序

板子:

 void merge_sort(int q[],int l,int r){
  if(l>=r) return ;
  int mid=r+l>>1;
  int k=0,i=l.j=mid+1;
  merge_sort(q,l,mid);
  merge_sort(q,j,r);
  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++];
  for(int i=0,j=1;j<=r;j++,i++) q[j]=tmp[i];
 }

scanf和cin

  1. 当有很多数需要读入的时候,最好使用scanf而不是cin

  2. scanf的速度比cin快十几倍甚至几十倍

  3. 如果是string类型,那么只能通过cin读入

二分查找

二分查找也称折半查找,它是一种效率较高的查找方式,但是二分查找要求线性表是采用顺序结构的。一般是一个有单调性的数组,但也不是绝对的。一般来说,有单调性的题目一定可以使用二分,没有单调性的题目也可能可以使用二分。

思想:一个有单调性的题目如果要满足某个条件,那么这个边界肯定是可以被二分出来的。

举一个简单的栗子:如果一个升序的线性表,我们要找到某个数的左边界,if(q[mid]>=x) 满足这个条件,且我们要找到的时候左边界,那么就把r=mid l=mid+1,直至找到。

整数二分板子:

 bool check(int x)  
 
 int bsearch_1(int l,int r){
    while(l<r) {
      int mid=l+r>>1;
      if(check(mid)) r=mid;
      else l=mid+1;
    }
    return l;
 }
 
 int bsearch_2(int l,int r){
    while(l<r){
      int mid=l+r+1>>1;
      if(check(mid)) l=mid;
      else r=mid-1;
    }
    return l;
 }

浮点数二分板子

 bool check(double x)
 double bsearch_3(double l,double r)
 {
  const double eps=1e-6
  while(r-l>eps)
  {
      double mid=(l+r).2;
      if(check(mid)) r=mid;
      else l=mid;
  }
  return l;
 }

关于精确位数

在处理浮点数的时候,我们通常计算到题目要求的精度的后两位,比如题目要求的答案是六位小数,那么我们计算的时候通常用的是八位小数。

高精度

关于高精度的说明

两个大数或者一个大数和一个小数的运算

大数是指几千位长度的数字,这种数明显是爆了longlong的,所以我们输入的时候应该使用string类型,存储的时候用vector

 vector <int> Add(vector<int> &A,vector<int> &B){
    vector<int> C;
    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(t);
    return C;
 }

先要比较a,b的大小,如果a<b,那么a-b=-(b-a)

 vector <int> sub(vector<int> A,vector<int> B){
  vector<int> C;
  for(int i=0,t=0;i<A.size();i++){
      t=A[i]-t;
      if(i<B.size()) t-=B[i];
      C.push_back((t+10)%10);
      if(t<0) t=1;
      else t=0;
  }
 }

大数乘小数

 vector <int> mul(vector<int> A,int b){
    vector <int> C;
    int t=0;
    for(int i=0;i<A.size();i++){
      t+=A[i]*b;
      C.push_back(t%10);
      t/=10;
    }
    while(t)
    {
      C.push_back(t%10);
      t/=10;
    }
 }

前面几种运算都是从低位进行运算,直到高位,而除法显然是从高位开始运算的,所以运算出的vector需要倒序

vector<int> div(vector<int> A,int b,int &c){
vector<int> C;
c=0;
for(int i=A.size()-1;i>=0;i--){
c=c*10+A[i];
C.push_back(c/b);
c%=b;
}
reverse(C.begin(),C.end());
}

 

 

 

引用传递

int func(int &a);
int main(){
int a;
func(a);
} //直接对a进行修改,而不是对a的副本进行修改
//引用传递和值传递的区别:
引用传递是直接对传入的变量或者数组等容器进行修改的,传递的过程中并不会拷贝一个副本,这样当我们传长度为几十万的数组或者更大的数据。就不会浪费空间。

vector(动态数组)

定义:长度可变的数组

常用操作:

vector <typename>   xxx ;  //定义一个vector  typename可以是简单的int 类型  也可以是数组之类的容器

几个常用的内置函数

vector.begin() //返回vector头地址

vector.end() //返回vector尾地址的后面一位
因为美国人的思维大多是左闭右开

vector.push_back(xxx) //末尾加入元素

vector.pop_back(xxx) //末尾删除元素

vector.insert(vector.begin()+3,xxx) //下表为3位置插入元素

vector.earse(vector.begin()+3) //下表为3位置删除元素

vector.size() //vector长度

vector.clear() //清除所有元素

//访问vector元素有两种方法

1.下标访问
vi[0] //和array一个用法

2.迭代器
for(vector<int>::iterator it=vi.begin();it!=vi.end();it++){
printf("%d",*it);
}

 

posted @   安妮的心动录  阅读(31)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示