[C/C++]-语法复习&秋招刷题记录

记录一些刷算法题中的常用C++语法和经典题型,作为复习和梳理。
上一篇踩坑记录:https://www.cnblogs.com/camilia/p/15743180.html
刷题目录和参考资料:代码随想录

STL相关

数据类型转换

vector<int>(ans.begin(),ans.end())
TODO 补充说明

Vector

初始化

头文件:#include <vector>
初始化:vector <数据类型> 变量名 (长度,初始化值)
赋值初始化:vector <数据类型> 变量名 = {1,2,3,4,5}

可以作为数组

数组开头:array.begin()
数组结尾:array.end()
数组大小:array.size()

增删

添加元素到尾部:array.push_back(x)
删除元素:
image

函数传参引用

vector<int>& array

Set

初始化

无序set初始化:unordered_set<int> s;
有序不重复:set
有序可重复:multiset
image
std::unordered_set底层实现为哈希表,std::set 和std::multiset 的底层实现是红黑树,红黑树是一种平衡二叉搜索树,所以key值是有序的,但key不可以修改,改动key值会导致整棵树的错乱,所以只能删除和增加

常见用法

  1. 哈希表:快速判断一个元素是否出现集合里的时候,可以考虑哈希表,空间换时间。
  2. 自动排序
  • 拥有去重的特性,增insert()、删erase()、查find()复杂度与哈希表相同,均为O(1)。

  • 优先使用unordered_set,因为它的查询和增删效率是最优的。拥有去重的特性,增insert()、删erase()、查find()复杂度与哈希表相同,均为O(1)。

  • 如果需要集合是有序的,那么就用set,如果要求不仅有序还要有重复数据的话,那么就用multiset。

Map

与set类似:
image
在map 是一个key value 的数据结构,map中,对key是有限制,对value没有限制的,因为key的存储方式使用红黑树实现的。

常见用法

  1. 哈希表:a中查找key不为空的条件a.count(key) > 0
  2. 计数器unordered_map<int, int> countx计数:count[x]++;

string

输入

可以用getline读取一行,读取到换行符'\n'时会结束返回。
输入的字符串内有空格:getline(cin, s),可以保留空格,s的数据类型是string;
加入参数,可以设置成停止符:getline(cin, s, ','),读取输入到','截止。

也可以把读入的输入字符串,转换成stringstream,再进行处理。

#include<sstream>

string line;
getline(cin, line);
stringstream ss(line);
while(getline(line, s, ',')){} //此时一行有多个字符串输入,中间用逗号隔开

获取长度

s.length()

指定位置子串

string substr = s.substr(start, num); //从index为start开始的num个字符。

删除指定字符

string substr = s.erase(s.begin() + j); //删除index=j的字符

进制转换

int num1 = stoi(str, 0, 2); //将字符串 str 从 0 位置之后的数字的 2 进制数,转换为十进制。参数分别为:被转换字符串、开始转换位置、原数制
int num2 = atoi(s.c_str());// atoi把参数 str 所指向的字符串转换为一个整数(类型为 int 型)。要先转化为const char*,默认转换都是十进制

字符转换

数字转换成字符串:

int num = 123456789;
string s = to_string(num);//s="123456789"

数据结构相关

链表

初始化

用结构体定义

struct ListNode {
    int val;  // 节点上存储的元素
    ListNode *next;  // 指向下一个节点的指针
    ListNode(int x) : val(x), next(NULL) {}  // 节点的构造函数
};

用默认模板定义

# 定义同时赋值
ListNode* head = new ListNode(5); //头节点,值为5。
# 定义完再赋值
ListNode* head = new ListNode();
head->val = 5;

删除元素

用C++写链表删除某个元素时要记得将删掉的元素释放内存。

//以头结点为例
ListNode* temp = head;
head = head->next;
delete temp;

链表 VS. 数组

image

C++语法相关

输入输出

遇到不定长输入时,可以用cin.get()读取换行符:

if(cin.get() == '\n'){
    //此时说明一行输入结束
}

注意!getline(cin,x)取输入时,取到换行符截止,所以在下一次读取时,需要把cin中剩下的换行符拿走。可以用cin.get()取一个字符,在程序末尾也可以用cin.ignore(100, '\n')
image

循环遍历

for (int i: arrays) i作为下标使用,类型int是arrays内的数据类型
for(auto & x : arrays) x是arrays的遍历值arrays[index]不是下标

指针

nullptr

用以解决NULL在隐式转换和作为函数传入参数时的二义性问题。
C和C++在处理void 类型的时候存在一定的区别。C语言中,void类型的变量可以赋值给任意类型的指针,也可以被任意类型的指针赋值,两个方向都不会报错。但是C++具有更严格的类型检查,前者是不被允许的。
参考:https://www.jianshu.com/p/09e3b40929ad

所以在初始化和判断空指针时最好使用nullptr

malloc

malloc函数返回值的类型是 void*,C不要求强制类型转换,会自动进行隐式转换,但是C++则需要,因为void*不能转换成其他类型的指针。

int len = 100;
int p = malloc(len * sizeof(int)); // C推荐做法
int p = (int )malloc(len * sizeof(int)); // C++推荐做法

常见考题

数组

二分查找

时间复杂度:O(n)->O(logn)
边界条件:

  • 结束查找的条件
  • 移动左右区间

依据:

  • 查找空间是闭区间还是开区间

快慢指针

通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。
时间复杂度: O(n^2)->O(n)
典型应用: 移除某个元素。
注意:数组在内存中是连续的地址空间。

滑动窗口

根据当前子序列和大小的情况,不断调节子序列的起始位置。

时间复杂度: O(n^2)->O(n)
边界条件:

  • 右指针移动直至窗口满足条件1
  • 左指针移动直至窗口满足条件2

典型应用: 查找子序列。

循环模拟

注意边界条件。

链表

虚头结点

遇到头结点需要单独处理的情况,例如删除某个节点,用虚头结点作为起始比较方便。

双指针法

遍历链表时经常新建一个指针来作为当前遍历的位置。
双指针法可以实现一遍遍历实现两遍遍历的功能,例如反转链表
快慢指针可以实现特定问题的设置,例如环形链表

哈希表

哈希表是根据关键码的值而直接进行访问的数据结构(数组)。哈希表中关键码就是数组的索引下标,然后通过下标直接访问数组中的元素。
可以由数组、Set、Map三种数据结构组成,三种方式要根据题目的特点选择:

  1. 数组的大小是受限制的,如果元素很少,哈希值太大会造成内存空间的浪费。适合key固定而且数量不多的情况。
  2. Set是一个集合,适合key数量不固定的情况。
  3. Map有键值,适合除了查询key也要保存key相关的情况。
posted @ 2023-06-05 15:36  CAMILIA  阅读(291)  评论(0编辑  收藏  举报