C++ LeetCode 刷题经验、技巧及踩坑记录【三】
- 前言
- vector 计数
- vector 逆序
- vector 删除首位元素
- vector二维数组排序
- vector二维数组初始化
- C++ 不同进制输出
- C++ 位运算
- C++ lower_bound()
- C++ pair
- C++ stack 和 queue
前言
记录一些小技巧以及平时不熟悉的知识。
vector 计数
计数
//记录与首元素相同的数字的个数,因为数组有序,并且最多出现4次,所以不用遍历所有区间
int cnt = count(nums.begin(), nums.begin() + 4, nums[0]);
vector 逆序
reverse(ans.begin(),ans.end())
或
{ans.rbegin(),ans.rend()}
vector 删除首位元素
vector<int> nums_new(nums.begin() + 1,
nums.end());//去掉一个首元素(顺子的第一个)
nums_new.erase(find(nums_new.begin(), nums_new.end(),
nums[0] + 1));//去掉一个首元素+1(顺子的第二个)
vector二维数组排序
#include <iostream>
#include <vector>
#include <algorithm>
bool customSort(const std::vector<int>& a, const std::vector<int>& b) {
if (a[0] < b[0]) {
return true; // 第一列升序排列
} else if (a[0] > b[0]) {
return false;
} else {
return a[1] > b[1]; // 第二列降序排列
}
}
void sortTwoDimensionalArray(std::vector<std::vector<int>>& arr) {
std::sort(arr.begin(), arr.end(), customSort);
}
如果是在类中使用,要将custom设为static 静态函数。原因如下:
为什么cmp函数在作为类成员函数的时候一定需要static修饰呢?这是因为所有我们在类内定义的非static成员函数在经过编译后隐式的为他们添加了一个this指针参数!变为了:
bool cmp(Solution *this, int a, int b)
而标准库的sort()函数的第三个cmp函数指针参数中并没有这样this指针参数,因此会出现输入的cmp参数和sort()要求的参数不匹配,从而导致了:
error: reference to non-static member function must be called
而我们知道static静态类成员函数是不需要this指针的,因此改为静态成员函数即可通过!
或者( LeetCode354官方题解 ):
sort(envelopes.begin(), envelopes.end(), [](const auto& e1, const auto& e2) {
return e1[0] < e2[0] || (e1[0] == e2[0] && e1[1] > e2[1]);
});
这个更简洁更易理解。
vector二维数组初始化
常用与动态规划中DP Table的建立。
以下代码将创建一个 i 行 j 列的二维矩阵,并全部初始化为-1。
dp = vector<vector<int>>(i, vector<int>(j, -1));
以下代码将创建一个 m+1 行 n 列的二维矩阵,默认初始化为 0。
vector<vector<int>> dp(m+1,vector<int>(n+1));
C++ 不同进制输出
C++中以四种进制进行输出
#include <iostream>
#include <bitset>
using namespace std;
int main()
{
int a=64;
cout<<(bitset<32>)a<<endl;//二进制32位输出
cout<<oct<<a<<endl;//八进制
cout<<dec<<a<<endl;//十进制
cout<<hex<<a<<endl;//十六进制
return 0;
}
C++ 位运算
参考
&
按位与
如果两个相应的二进制位都为1,则该位的结果值为1,否则为0
|
按位或
两个相应的二进制位中只要有一个为1,该位的结果值为1
^
按位异或
若参加运算的两个二进制位值相同则为0,否则为1
~
取反
~是一元运算符,用来对一个二进制数按位取反,即将0变1,将1
举例:
1000101 1000101 1000101 1000101
& 0101100 | 0101110 ~ ^ 0101110
= 0000100 = 1101111 = 0111010 1101011
<<左移运算符:expr1<<expr2 表示 expr1 左移 expr2 位,数值上表示 expr1 扩大了 2^expr2 倍;
>> 右移运算符:expr1>>expr2表示 expr2 右移 expr2 位,数值上表示 expr1 缩小了 2^expr2 倍;
左移就是扩大 2 移位数 2^{移位数} 2移位数 ,右移就是缩小 2 移位数 2^{移位数} 2移位数
- 左移运算符
左移运算符为:<<
将一个运算对象的各二进制位全部左移若干位;
左边的二进制位丢弃,右边补0;
若左移时舍弃的高位不包含1,则每左移一位,相当于该数乘以2。 - 右移运算符
右移运算符为:>>
将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃;
操作数每右移一位,相当于该数除以2;
左补0还是补1,得看被移数是正还是负。 - 总结
number << n; // number乘以2的n次幂
number >> n; // 如果number为非负,则用number除以2的n次幂
这些移位运算符类似于十进制中移动小数点来乘以或除以10
应用:将十进制转为二进制并统计二进制中1的位数。
C++ lower_bound()
参考
C++ STL标准库中除了基于顺序查找的 find()、find_if()、search() 等,还提供有 lower_bound()、upper_bound()、equal_range() 以及 binary_search() 这 4 个查找函数,它们的底层实现采用的都是二分查找的方式。
lower_bound() 函数用于在指定区域内查找不小于目标值的第一个元素。也就是说,使用该函数在指定范围内查找某个目标值时,最终查找到的不一定是和目标值相等的元素,还可能是比目标值大的元素。
lower_bound() 函数定义在头文件中,其语法格式有 2 种,分别为:
//在 [first, last) 区域内查找不小于 val 的元素
ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last,
const T& val);
//在 [first, last) 区域内查找第一个不符合 comp 规则的元素
ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last,
const T& val, Compare comp);
其中,first 和 last 都为正向迭代器,[first, last) 用于指定函数的作用范围;val 用于指定目标元素;comp 用于自定义比较规则,此参数可以接收一个包含 2 个形参(第二个形参值始终为 val)且返回值为 bool 类型的函数,可以是普通函数,也可以是函数对象。
实际上,第一种语法格式也设定有比较规则,只不过此规则无法改变,即使用 < 小于号比较 [first, last) 区域内某些元素和 val 的大小,直至找到一个不小于 val 的元素。这也意味着,如果使用第一种语法格式,则 [first,last) 范围的元素类型必须支持 < 运算符。
此外,该函数还会返回一个正向迭代器,当查找成功时,迭代器指向找到的元素;反之,如果查找失败,迭代器的指向和 last 迭代器相同。
再次强调,该函数仅适用于已排好序的序列。所谓“已排好序”,指的是 [first, last) 区域内所有令 element<val(或者 comp(element,val),其中 element 为指定范围内的元素)成立的元素都位于不成立元素的前面。
例子
#include <iostream> // std::cout
#include <algorithm> // std::lower_bound
#include <vector> // std::vector
using namespace std;
//以普通函数的方式定义查找规则
bool mycomp(int i,int j) { return i>j; }
//以函数对象的形式定义查找规则
class mycomp2 {
public:
bool operator()(const int& i, const int& j) {
return i>j;
}
};
int main() {
int a[5] = { 1,2,3,4,5 };
//从 a 数组中找到第一个不小于 3 的元素
int *p = lower_bound(a, a + 5, 3);
cout << "*p = " << *p << endl;
vector<int> myvector{ 4,5,3,1,2 };
//根据 mycomp2 规则,从 myvector 容器中找到第一个违背 mycomp2 规则的元素
vector<int>::iterator iter = lower_bound(myvector.begin(), myvector.end(),3,mycomp2());
cout << "*iter = " << *iter;
return 0;
}
程序执行结果为:
*p = 3
*iter = 3
注意,myvector 容器中存储的元素看似是乱序的,但对于元素 3 来说,大于 3 的所有元素都位于其左侧,小于 3 的所有元素都位于其右侧,且查找规则选用的是 mycomp2(),其查找的就是第一个不大于 3 的元素,因此 lower_bound() 函数是可以成功运行的。
C++ pair
pair将一对值(T1和T2)组合成一个值,
这一对值可以具有不同的数据类型(T1和T2),
两个值可以分别用pair的两个公有函数first和second访问。
C++ stack 和 queue
头文件
#include<queue>// 队列
#include<stack>//栈
定义
stack<int> s;
queue<int> q;
常用操作
栈:
s.empty()//如果栈为空返回true,否则返回false
s.size()//返回栈中元素的个数
s.pop()//删除栈顶元素但不返回其值
s.top()//返回栈顶的元素,但不删除该元素
s.push(X)//在栈顶压入新元素 ,参数X为要压入的元素
队列:
q.empty()// 如果队列为空返回true,否则返回false
q.size() // 返回队列中元素的个数
q.pop() //删除队列首元素但不返回其值
q.front() // 返回队首元素的值,但不删除该元素
q.push(X) //在队尾压入新元素 ,X为要压入的元素
q.back() //返回队列尾元素的值,但不删除该元素
两栈实现队和两队实现栈是常见的简单题,画个图就好了,要点是两个栈(或栈)做好分工,有主次的去使用。