一、字符串
字符串扩容:size()是已经拥有的元素大小,而capacity()是能够装下的元素大小。resize(n)是创建了n个元素,reverse(n)是申请了n个元素的空间,不可以直接访问。
双指针,i j按照一定条件移动
字符串反转:reverse[first, last)
class Solution {
public:
bool integer(string s) {
//判断是否是整数
int size = s.size();
int posOpr = -1;
for(int i = 0; i < size; ++i) {
if(i == 0 && (s[i] == '+' || s[i] == '-')) {
posOpr = 0;
continue;
}
if(s[i] < '0' || s[i] > '9') return false;
}
if(posOpr == size - 1) return false;
else return true;
}
bool decimal(string s) {
//判断是否是小数
int size = s.size();
if(size < 2) return false;
int posPoint = -1, posOpr = -1;
for(int i = 0; i < size; ++i) {
if(s[i] == '.') {
posPoint = i;
break;
}
}
if(posPoint == -1) return false;
for(int i = 0; i < size; ++i) {
if(i == 0 && (s[i] == '+' || s[i] == '-')) {
posOpr = 0;
continue;
}
if(i != posPoint && (s[i] < '0' || s[i] > '9')) return false;
}
if(posPoint == size - 1) {
if(s[posPoint - 1] < '0' || s[posPoint - 1] > '9') return false;
}
if(posOpr == size - 1) return false;
else return true;
}
bool isNumber(string s) {
//判断有没有e/E,没有的话可以整个视为整数or小数,有的话分为整数/小数 e/E 整数
int size = s.size();
int start = -1, index = -1, end = -1;
//去除前空格
for(int i = 0; i < size; ++i) {
if(s[i] != ' ') {
start = i;
break;
}
}
//去除尾空格
for(int i = size - 1; i >= 0; --i) {
if(s[i] != ' ') {
end = i;
break;
}
}
if(start == -1 || end == -1) return false; //全是空格
//查找是否有断点E/e
for(int i = start; i <= end; ++i) {
if(s[i] == ' ') continue;
if(s[i] == 'e' || s[i] == 'E') {
index = i;
break;
}
}
if(index == -1) {
string str = s.substr(start, end - start + 1);
if(integer(str) || decimal(str)) return true;
}
else {
if(index == end || index == start) return false;
string str1 = s.substr(start, index - start);
string str2 = s.substr(index + 1, end - (index + 1) + 1);
if((integer(str1) || decimal(str1)) && integer(str2)) return true;
}
return false;
}
};
模拟题一直是我的弱项,分块的思想去做,然后debug会好做一点。主要的思路:判断有没有e/E,没有的话可以整个视为整数or小数,有的话分为整数/小数 e/E 整数。此外'+' '-'和‘.’的小数情况容易漏,这道题应该是hard难度。
二、链表
链表反转:p1 p2 和临时tmp
数组反转:reverse(res.begin(), res.end())
堆:反转输出第一时间要想到栈 stack
链表反转,如果面试出了这个,大概面试官很想要我0.0
1、暴力方法:遍历第一次解决next,并设置两个哈希表,由老链表节点-顺位 顺位-新链表节点,第二次遍历把random解决。
2、unordered_map的用法:
初始化:unordered_map<int, string> mp
插入:mp[value] = keyname; 对应value的keyname值覆盖,若value不存在,则插入这对元素
mp.insert(pair<int, string>(value, keyname));
查找:auto x = mp.find(value); x->first x->second
三、双指针
根据value删除结点,两个注意事项:需要删除的节点是头结点还是中间节点;中间节点循环的条件。
倒数数字的前一位 = 链表总数 - 倒数数字
双指针:设置链表头,使得头结点的比较和中间节点一致
双指针比较节点
有点快排的味道
两数之和的题,还加了个递增的限制条件
去除头、中间、末尾的空格,然后反转单词,再整体反转。在反转单词时最后一个单词不会反转需要注意。
string用法:
子串:s.substr(pos, n); 由pos开始的n个字符组成的字符串
拼接:string str = str1 + str2
访问字符串字符:str[2] str.at(2)
插入:str.insert(pos, const string&str); 在位置 pos 处插入字符串 str
删除:str.erase(pos, n); 在位置 pos 处插入字符串 str
四、栈与队列
两个栈实现一个队列,入栈放在stk1,出栈先判断stk2是否为空,如果为空,则把stk1全部移入再出栈,然后不为空则直接出栈.
思路:一个辅助栈用于记录当前的最小值
思路:保证deque中是非递增,双指针,左指针考虑nums[left - 1]和deque.front是否相同,右指针保证取到的值在deque处于非递增。
deque的用法:
front() 返回头部第一个元素
back() 返回尾部第一个元素
push_back(num) 尾部添加元素
push_front(num) 头部添加元素
pop_back(num) 删除容器最后一个元素
pop_front(num) 删除容器第一个元素
insert(pos, num) 在pos位置插入一个num元素
erase(begin(), end()) 删除区间的数值,返回下一个数据的位置
erase(pos) 删除pos位置的数据
queue的用法:
push(num) 队尾添加元素
pop() 队头删除元素
front() 返回队头第一个元素
back() 返回队尾第一个元素
deque实现单调队列
五、搜索与回溯
广度优先遍历:层序遍历(迭代法)
深度优先遍历:先序遍历、中序遍历、后序遍历(递归法、迭代法)
递归模板:
- 确定递归函数的参数和返回值
- 确定终止条件
- 确定单层递归的逻辑
原本的root->left会被替换,所以一开始需要保存。
回溯+DFS图搜索
回溯模板:
- 回溯函数模板返回值以及参数
- 回溯函数终止条件
- 回溯搜索的遍历过程
for循环可以理解是横向遍历,backtracking(递归)就是纵向遍历
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
本题思路:
- 使用二维bool数组记录之前的位置是否已经被访问过,如果已经被访问过,说明此路不通;
- 剪枝:当前遍历到的 board[i][j] 不等于word对应位置的字符,说明此路也是不通的;
- 递归地去 board[i][j] 的上下左右四个方向去找路径;
- 递归结束的条件:str == word 成立,说明找到这条路径,此时返回 true
使用广度优先搜索(BFS)
求取每个数字的位数:x%10 x/10