ll与int
- 造成二分查找无法退出,当r,l为ll类型,而mid声明为int类型
变量重复声明
- 会导致越界错误,结果错误等。调试时会发现某个值突然很大,有可能是重复声明导致的。
- n,m这些变量不要声明为全局变量,每个函数里自定义,这点时间复杂度不影响。
引用的swap使用
比如一个函数中
bool func(vector<vector<int>>&presum1,vector<vector<int>>&presum2){
swap(presum1,presum2);
}
这样的使用会导致presum1和presum2中下一次调用时的真正指向的数组已经swap,如果换成指针就可以避免下次调用时还是原来的。
为了在使用引用时也可以swap,可以加一个bool变量,进入这个函数时看一下是否被swap过。
bool flag = false;
bool func(vector<vector<int>>&presum1,vector<vector<int>>&presum2,int a,int b,int c,int d,int n){
if(flag){
swap(presum1,presum2);
flag = false;
}
//万一要执行swap操作就将flag置为true
}
vector
resize
dist.resize(n,inf);//错误用法,只有超出原本大小的元素会被置为inf,并不是每次执行会将所有元素置为inf
push_back更好用
vector中不支持二维向量使用emplace_back({2,4});这样的操作,而push_back是可以的,所以我们就只用push_back。
背包
优化空间时的第二层容量的循环,必须从大到小遍历,而不是从小到大遍历
set操作
(1)不能一边遍历,一边删除元素和插入元素
这倒不是因为会发生迭代器失效的情况,主要是——
- 在遍历过程中删除元素有可能会删除尚未遍历到的元素,导致我们遍历的结果会漏掉一些本应该遍历到的元素。(删除元素只会导致该位置的迭代器失效,其他元素的迭代器依然有效,元素在内存中的位置不变,迭代器只是会修改元素之前的相互指针)。
tips: 已删除迭代器取值(*)会触发coredump,因为对应空间已经被释放,然而it++是可以操作的,即对一个已经erase的迭代器执行++操作允许。 - 在遍历过程中插入元素有可能导致后续遍历到刚插入的元素,遍历个数增加。
(2)对于set来说,自带去重功能,自定义比较函数后,如果比较函数中的值相同,虽然插入的元素不同(比较的值相同),也只会插入一个元素,不会将两个不同的元素都插入。
vector
不能一边删除一边遍历
因为删除时该位置后面的迭代器都会失效,后续元素的位置会发生变化,导致下一步遍历的元素不是我们希望遍历的位置
参考视频
指针的使用
for(int i = 1;i<n;i+=2){
int l = i;
int r = n-1-l;
vector<TreeNode*> left = allPossibleFBT(l);
vector<TreeNode*> right = allPossibleFBT(r);
//注释了的是错误的方法
for(int j = 0;j<left.size();j++){
//root->left = left[j];
for(int k = 0;k<right.size();k++){
//root->right = right[k];
ret.emplace_back(new TreeNode(0,left[j],right[k]));
//root = new TreeNode(0);
}
}
}
位运算
正确写法
判断某一位是否为1,如果为1则...
if(i>>j & 1){
}
错误写法,结果正确,但是逻辑上不正确
判断某一位是否为1,如果为1则...
if(i>>j & 1 > 0){
}
优先级顺序为: 右移运算> 比较符 > 按位与
那么实际上执行的是((i>>j) & (1>0)),操作结果还是 ((i>>j)&1)),结果与正确写法相同
思维易错题整理
https://mirror.codeforces.com/contest/1974/problem/D