PAT算法笔记

ⅰ亾dé卋堺 提交于 2019-12-21 20:05:42

知识点总结

  • 定义之后一定要初始化

  • 尽量都使用vector,速度vector>set>map

  • 两个关键字排序简洁写法

    return (cnt!=a.cnt)?cnt>a.cnt:value

  • 使用10*1.0的方式去输出小数,除非必要。否则可以不用定义double

  • 一定要考虑到为01这些边界条件

  • 传参数尽量使用引用来加快速度

  • 先存进vector再排序比直接使用set要快

  • 将字母编号时。字母和数字都进行映射,这样方便根据字母取数字,根据数字取字母

  • 堆栈不要用for

  • 设置无限大统一使用10亿

  • 尽量使用c的输出。必要时输入输出可以C/C++混用

  • string name(ch) 将字符数组ch转化为string字符串

  • printf("%%"); 打印一个%

  • string.c_str(),将string类型转化为char*类型,以便printf()输出。

  • auto - 声明变量时根据初始化表达式自动推断该变量的类型,少了初始化就会出错

  • getline (cin,name) - 以'\n'结束

  • int - 10^9

    long long - 10^18

    long long类型常量需要在后面加上LL

    long long bignum=1234456789097LL

  • 碰到浮点都用double

  • while(get(str) !=NULL)

  • 宏定义后面不需要加分号

  • 使用数学函数加math.h

  • \0的ASCII码为零,即NULL

  • 运行错误可能是因为数组开小了

  • 如果数组有10^6需要定义在主函数外面

  • getcharputchar来输入输出单个字符,可以读取回车

  • 在多个测试案例时注意重置变量与数组(使用memsetfill函数)

  • void change(int a[],int b[][5]) 数组作为参数时,数组的第一维不需要填写长度

  • A ? B : C; 如果A为真,那么执行并返回B的结果;反之执行并返回C的结果

  • 除了%cscanf对其他格式符的输入是以空白格(空格,换行等)为结束判断标志

    %c是可以读入空格跟换行的

  • putsprintf通过\0来作为字符串结束的输出的,所以输出时要保证字符串结尾有\0,否则printf会因无法识别字符串而输出乱码

  • vector prime(500000,1); vector初始化

  • 处理大数运算时,对每一个字符的运算可以先减‘0’使其变成数字去运算,运算结果出来后再加'\0'使其变回字符串

  • 堆是一个完全二叉树,要用数组存储

  • 一般学号或者编号的题注意打印格式

  • 尽量使用fill(),少使用meset()

  • 无穷大: const int INF = 100000000;

  • typedef给数据类型起别名

    typedef long long LL;

  • memset对数组数组中的元素赋相同的值,需要添加string.h头文件,建议赋值位0-1

    memset(数组名,值,sizeof(数组名));

  • gets输入一行,gets识别换行符\n位输入结束。scanf完一个整数后,如果要受用gets,需要先用getchar接受整数后面的换行符

  • getline,gets[参考]

    getline(cin,query);

    cin.getline(S1,10010); S1为数组,10010是数组大小

    gets(m); m是字符数组(不推荐)

  • scanfcin都以空白格为结束标志,不会读取他们,所以它们会遗留在读取缓存中。但是只有在scanfgets使用或cin使用后紧接着又使用getline时,就需要吸收掉它们后面的字符tmp=getchar()[参考]

  • string.h头文件

    strcmp()比较两个字符串

    1. 字符串1<字符串2 返回负数
    2. 字符串1=字符串2 返回0
    3. 字符串1<字符串2 返回正数

    strcpy(str1,str2)把字符串2复制给1,包括\0

    strcat(str1,str2)把字符串2接到1后面

    截取子串

    1. s.substr(pos, n) 截取s中从pos开始(包括0)的n个字符的子串,并返回
    2. s.substr(pos) 截取s中从从pos开始(包括0)到末尾的所有字符的子串,并返回
  • intstring转换

  voidtestTypeConvert()
  {
      //int --> string
      inti = 5;
      string s = to_string(i);
      cout << s << endl;
      //double --> string
      doubled = 3.14;
      cout << to_string(d) << endl;
      //long --> string
      longl = 123234567;
      cout << to_string(l) << endl;
      //char --> string
      charc = 'a';
      cout << to_string(c) << endl;   //自动转换成int类型的参数
      //char --> string
      string cStr; cStr += c;
      cout << cStr << endl;
   
      s = "123.257";
      //string --> int;
      cout << stoi(s) << endl;
      //string --> int
      cout << stol(s) << endl;
      //string --> float
      cout << stof(s) << endl;
      //string --> doubel
      cout << stod(s) << endl;
  }
  • 字母转换大小写
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main()
{
  string str="how are you";
  transform(str.begin(),str.end(),str.begin(),::toupper);   //转大写
  transform(str.begin(), str.end(), str.begin(), ::tolower); //转小写
  cout << str << endl;
  return 0;
}
  • 随机函数
  #include <stdio.h>
  #include <stdlib.h>
  #include <time.h>
  #include <math.h>
  int main()
  {
      int left=1000,right=6000;
      srand((unsigned)time(NULL));     //生成随机种子
  		//可用于生成快排的主元 
      int rd=(int)(round(1.0*rand()/RAND_MAX*(right-left)+left)); //随机生成left-righth中的一个值
      printf("%d\\n",rd);
      return 0;
  }
  • 结构体定义与初始化
  //定义
  struct person{
      int ID;
      char name[10];
  };
  //定义并且定义变量
  struct person{
      int ID;
      char name[10];
  }myj={0,"myj"},students[2]={10,"BISEN",11,"zhiming"};   //定义一个变量或者数组
  //定义并且初始化
  struct person{
      int ID;
      char name[10];
  };
  struct person{
      int ID;
      char name[10];
      person(int _ID,char _name[10])    //定义初始化函数
      {
          ID=_ID;
          strcpy(name,_name);
      }
  }*p;      //定义一个结构体指针,用p->ID访问ID变量
  person student=person(10,"LILI");  //定义并初始化
  • scanf
int %d
long long %lld
float %f
double %lf
char %c
  • printf
int %d
long long %lld
float %f
double %f
char %c
  • 输出格式
%md 使不足m位的int变量以m位进行右端对齐,高位用空格补齐。如果超过m位择保持原样
%0md 不足m位时在右边补零
  • 常用数学函数
fabs(double x) 取绝对值
floor(double x) ceil(double x) 向下取整 向上取整
pow(double x) 求幂
sqrt(double x)
sin(double x) cos(double x) tan(double x)
round(double x) 四舍五入

C++ STl总结

vector:可变长数组

只有vectorstring才允许vi.begin()+3这种迭代去加上整数的写法

vector常见用途

  1. 存储数据
    • 使用在元素不确定的场合
    • 保存部分输出,最后输出在同一行输出
  2. 用邻接表存储图

vector常用函数

  • push_back() - 在vector后面加上一个元素
  • pop_back() - 在vector后面删除一个元素
  • size()
  • clear() - 清除所有元素
  • inster(it,-1) - vi.insert(vi.begin()+2,-1) 在任意迭代器处插入元素,复杂度O(N)
  • erase()
    • erase(it) - 删除单个元素,删除迭代器it处的元素
    • erase(first,last) 删除[first,last)区间内所有元素
#include <iostream>
#include <vector>       //要加头文件
using namespace std;
int main()
{
  vector<int> name;        //可下标访问:name[3]
  //定义vector数组,一维长度n被固定,二维才是可变的
  vector<vector<int> > Arry[100];      //二维vector >> 之间要加空格

  for(int i=0;i<5;i++)     
    name.push_back(i);    //添加元素

  vector<int>::iterator it=name.begin();    //vector迭代器

  for(int i=0;i<5;i++)     
    printf("%d\n",*(it+i));     //通过迭代器访问
  return 0;
}

set:内部自动有序且不含重复元素

set使用方法详细常用[参考]

set集合的交并补[参考2]

set常见用途

自动去重并按升序排列。要处理不唯一的情况适用multiset

set常用函数

  • insert(x) - 复杂度O(logN)
  • find(value) - 返回set中对应值为value的迭代器,找不到就返回vi.end() 复杂度O(logN)
  • erase()
    • erase(it) erase(value) - 根据迭代器和值去删除。 vi.erase(vi.find(100))
    • erase(first,last) 删除[first,last)区间内所有元素
  • size()
  • clear()
#include <iostream>
#include <set>       //要加头文件
int main()
{
    //定义
		set<int> name;
    return 0;
}

string

  • substr(pos,len) - 返回从pos号位开始,长度为len的字串
  • find()
    • str1.find(str2) - str2str1字串返回第一次出现的位置,否则返回-1
    • str1.find(str2,pos) - 从str1pos号位开始匹配str2,返回值与👆相同 复杂度O(nm)
  • replace() - str1.replace(pos,len,str2)str1pos号位开始,长度为len的字串替换为str2
  • erase()
    • erase(it)
    • erase(first,last) 删除[first,last)区间内所有元素
  • length()
  • size()
  • clear()
#include <iostream>
#include <string>       //要加头文件
using namespace std;
 
int main()
{
    //string定义
    string str="abc";
    
    //整个的输入输出只能通过cin cout
    cin>>str;
    cout<<str<<endl;
    
    //使用printf打印string。通过下标访问
    for(int i=0;i<str.length();i++)
    {
        printf("%c",str[i]);
    }
    
    //迭代器访问
    for(string::iterator it=str.begin();it!=str.end();it++)
    {
        printf("%c\n",*it);
    }
    
    //string支持两个字符串直接x相加
    string str1="12";
    string str2="34";
    str=str1+str2; 
    
    //string可以直接进行比较
    int p=str1>str2;
    cout<<p<<endl;
    return 0;
}

map

注意事项:在map中,由key查找value时,首先要判断map中是否包含key。[参考]

map中的元素是自动按Key升序排序,所以不能对map用sort函数

map常见用途:

  1. 需要建立字符串与整数之间映射的题目
  2. 判断大整数或者其他数据类型是否存在的题目,可把mapbool数组使用
  3. 字符串映射到字符串
  4. map可以代替hash的使用

map可以将任何基本类型映射到任何基本类型

会自动以键从小到大自动排序

  • find(key) - 返回键为key的映射的迭代器,不存在就返回end函数返回的迭代器 复杂度O(logN)
  • erase()
    • mp.erase(it)
    • mp.erase(key) - 复杂度O(logN)
    • erase(first,last) 删除[first,last)区间内所有元素
  • size()
  • clear()
#include <iostream>
#include <map>       //要加头文件
#include <set>
using namespace std;
 
int main()
{
    //定义 map<typename1,typename2> mp;
    map<string,int> mp;     //字符串到整形发的映射,不能使用char
    map<set<int>,string> mp2;
    map<char,int> mp3;
    
    //赋值,
    mp3['c']=10;     //键只能有一个,当赋值时内部存在则修改,不存在就新建
    mp['m']=20;


    for(map<char,int>::iterator it=mp3.begin();it!=mp3.end();i++)
    {
        printf("%c %d\n",it->first,it->second);
    }

		//map与set组合使用,这样一个键可以对应多个值
		map<string,set<int> > m;
    m["book"].insert(123);
    set<int>::iterator it=m["book"].begin();
    printf("%d\n",*it);
    return 0;
}

unordered_map

待补充[参考]


queue

  • push()
  • pop()
  • front()
  • back()
  • empty()
  • size()

front()pop()使用前要使用empty()判断队列是否为空


priority_queue

  • push()
  • pop()
  • top()
  • empty()
  • size()

使用top()必须用empty()判断是否为空

默认是最大堆

元素优先级设置

#include <iostream>
#include <queue>       //要加头文件
using namespace std;
int main()
{
    priority_queue<int> q;
		//是double第二个参数就要变成vertor<double> 
		//less<int> 表示数字大的优先级越大   greater<int> 数字小的优先级大
		priority_queue<int,vertor<int>,less<int> > q;		    
    return 0;
}

结构体优先级设置

#include <iostream>
#include <queue>       //要加头文件
#include <string>
using namespace std;
struct fruit{
    string name;
    int price;
    
    friend bool operator < (fruit f1,fruit f2)  //只需要重载小于号就行了
    {
        return f1.price>f2.price;      //与排序的比较函数写法相反
    }
}f1,f2;

int main()
{
    priority_queue<fruit> q;
    f1.name="桃子";
    f1.price=3;
    f2.name="梨子";
    f2.price=1;
    
    q.push(f1);
    q.push(f2);
    cout<<q.top().name<<" "<<q.top().price<<endl;
    return 0;
}


stack

  • push()
  • pop()
  • top()
  • empty()
  • size()

pop()top()之前需要使用empty()去判断是否为空

#include <iostream>
#include <stack>       //要加头文件
using namespace std;
 
int main()
{
    //定义
    stack<int> s;
    return 0;
}


pair:有两个元素的结构体

头文件:#include <map>

pair可以直接使用== <去比较,规则是先firstsecond比较

pair用途:

  • 替代二元的结构体
  • 作为map的键值进行插入

创建:

pair(5,"hah")

make_pair(5,"hah")


algorithm

  • max(x,y) min(x,y) max(x,mac(y,z))

  • abs(x) - x必须是整数

  • swap()

  • reverse(it,it2)

  • sort() - 可对vector,string,deque使用

    第三个参数可不写,默认升序

    比较函数:如果第一个参数排在第二个参数前面,返回true,否则返回false

    a<b就是排序规则,满足就返回true,不交换。反之亦然

    a==b是尽管返回false 但是它不会位置调换

    sort函数中的陷阱:永远让比较函数对相同元素返回false。return a<=b //错误写法

bool compare(int a,int b)
{
	return a<b; //升序排列,如果改为return a>b,则为降序
}

  • next_permutation() - 给出一个序列在全排列中下一个序列
  #include <iostream>
  #include <algorithm>       //要加头文件
  using namespace std;
  
  int main()
  {
      int a[10]={1,2,3};
      
      do{
          printf("%d%d%d\\n",a[0],a[1],a[2]);
      }while(next_permutation(a,a+3));
      
      return 0;
  }

  • fill() - 把数组区间赋值为某个值
  #include <iostream>
  #include <algorithm>       //要加头文件
  using namespace std;
  
  int main()
  {
      int a[10]={1,2,3,4,5};
      fill(a,a+5,1);
      
      return 0;
  }

  • lower_bound() upper_bound() 在有序容器中

    lower_bound(first,last,val) - 寻找[first,last)区间内第一个值大于等于val的元素位置。是数组返回指针,容器就返回迭代器

    upper_bound(first,last,val) - 寻找[first,last)区间内第一个值大于val的元素位置。是数组返回指针,容器就返回迭代器

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!