目录
1.accumulate
2.__builtin_ctz / __builtin_ctzll
3.__builtin_clz / __builtin_clzll
3.__builtin_popcount
4.bitset
4.1 参数
4.2 构造函数
4.3 成员函数
4.4 bitset的应用
5.lower_bound / upper_bound
6.min_element / max_element
7.iota
8. next_permutation
9. stringstream
持续更新中......
①求和:
第三个参数作为初始值,将区间[first, end)的值相加,返回初始值加上区间总和的值。
需要注意的是,如果总和超出区间中数的类型范围,可以将第三个参数强转成64位的long long类型
#include
#include // std::accumulate #include int main() { int init = 0; std::vector nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; std::cout << std::accumulate(nums.begin(), nums.end(), init); //output:55 return 0; } ②自定义:
第三个参数传入函数或者对象,自定义函数包含两个参数,第一个参数为初始值,第二个参数将依次传入范围中的值,具体看代码注释;如果是对象,可在在对象中重载operator()实现上述功能
#include
#include // std::accumulate #include template class myclass { public: int operator()(T x, T y) { return x + 3 * y; } }; int main() { int init = 0; std::vector nums = { 100, 200, 300}; std::cout << std::accumulate(nums.begin(), nums.end(), init, [&](int x, int y) { return x + 2 * y; }) << std::endl;; //output:55 //output: 0 + 100 * 2 + 200 * 2 + 300 * 2 = 1200 std::cout << std::accumulate(nums.begin(), nums.end(), init, myclass ()); //output: 0 + 100 * 3 + 200 * 3 + 300 * 3 = 1800 return 0; }
__builtin系列的函数为GCC编译器的内联函数;
__builtin_ctz:用于计算一个32位数中后导零的数量
cout << __builtin_ctz(16); //16: 10000 ---> output:4
__builtin_ctzll:用于计算一个64位数中后导零的数量
cout << __builtin_ctzll(1LL << 40); //output: 40
__builtin_clz :用于计算一个32位数的前导零数量
cout << __builtin_clz(8); //(0000 0000 0000 0000 0000 0000 0000 1000) --> output: 28 int LOG = 31 - __builtin_clz(8); //LOG = 3 --> 2^3 = 8
对于一个不是2的幂的数,求它以2为底的对数,用上述第二段代码求得的是向下取整之后的值
int LOG = 31 - __builtin_clz(15); //(0000 0000 0000 0000 0000 0000 0000 1111) LOG = 3
__builtin_clzll:用于计算一个64位数的前导零数量
用于计算一个数的二进制中1的个数
cout << __builtin_popcount(15); //output: 4
bitset类模拟了存放bool类型的array ,但是对其做了空间优化,每个元素0或1都只占用了一个位,并且可以用 [ ] 访问每一位的值
4.1 参数
4.2 构造函数
#include
#include #include int main() { std::bitset<16> foo; std::bitset<16> bar(0xfa2); std::bitset<16> baz("0101111001"); std::cout << foo; //output:0000000000000000 std::cout << bar; //output:0000111110100010 std::cout << baz; //output:0000000101111001 return 0; } 4.3 成员函数
①set()
用法:1.将所有位设置成1; 2.将指定位设置成0或1(默认为1)
②reset()
用法:1. 将所有位设置成0 ; 2.将指定位设置成0;
③operator[]
int main() { std::bitset<8> bs; for (int i = 0; i < bs.size(); i++) { bs[i] = 1; } std::cout << bs; //output: 11111111 }
④count 返回1的个数
int main() { std::bitset<8> bs(15); std::cout << bs.count(); //output: 4; }
⑤to_string 转为string类型
⑥to_ullong 转为 unsigned long long类型
其他:bitset - C++ Reference (cplusplus.com)
4.4 bitset的应用
① 快速擦找大量数据是否在一个集合总
② 求两个集合的交集
③操作系统中的磁盘块标记
④排序去重
C++标准库自带的二分查找算法,对于lower_bound(val),函数返回 [first, last) 范围内val下限(第一个大于等于val)位置的迭代器,而upper_bound则是返回 [first, last) 范围内val上限(第一个大于val)位置的迭代器
#include
// std::cout #include // std::lower_bound, std::upper_bound, std::sort #include // std::vector int main() { int myints[] = { 10,20,30,30,20,10,10,20 }; std::vector v(myints, myints + 8); // 10 20 30 30 20 10 10 20 std::sort(v.begin(), v.end()); // 10 10 10 20 20 20 30 30 std::vector ::iterator low, up; low = std::lower_bound(v.begin(), v.end(), 20); up = std::upper_bound(v.begin(), v.end(), 20); std::cout << "lower_bound at position " << (low - v.begin()) << '\n'; //output: 3 std::cout << "upper_bound at position " << (up - v.begin()) << '\n'; //output: 6 return 0; } 需要注意的是,对于如vector这类支持随机迭代器的容器使用lower_bound/upper_bound函数的时间复杂度为logN, 而对于set/multiset这类不支持随机迭代器的容器,使用库函数的lower_bound/upper_bound函数的时间复杂度为N* logN,
而set/multiset中也有实现二分查找的同名成员函数,时间复杂度为logN
算法运用:有序集合 + 滑动窗口
2817. 限制条件下元素之间的最小绝对差220. 存在重复元素 III
返回区间 [first, last) 中最小值的迭代器
// min_element/max_element example #include
// std::cout #include // std::min_element, std::max_element #include int main() { std::vector arr = { 3,7,2,5,6,4,9 }; // using default comparison: std::cout << "The smallest element is " << *std::min_element(arr.begin(), arr.end()); std::cout << "The largest element is " << *std::max_element(arr.begin(), arr.end()); return 0; }
见文章【C++】iota函数 + sort函数实现基于一个数组的多数组对应下标绑定排序_Dusong_的博客-CSDN博客
按字典序的到全排类的下一个排列,如果函数可以将对象重新排列为字典上更大的排列,则返回 true。否则,该函数返回 false 以指示排列不大于前一个排列
#include
#include
#include
using namespace std;
int main() {
vector arr = { 2, 1, 3 };
sort(arr.begin(), arr.end());
do {
for (auto x : arr) cout << x << ' ';
cout << endl;
} while (next_permutation(arr.begin(), arr.end()));
return 0;
}
例题:leetcode 46.全排列
法一:回溯
class Solution {
public:
vector> permute(vector& nums) {
int n = nums.size();
vector> ans;
vector path(n), vis(n, false);
function dfs = [&](int i) -> void {
if (i == n) {
ans.push_back(path);
return;
}
for (int j = 0; j < n; j++) {
if (!vis[j]) {
path[i] = nums[j];
vis[j] = true;
dfs(i + 1);
vis[j] = false;
}
}
};
dfs(0);
return ans;
}
};
法二:库函数
class Solution {
public:
vector> permute(vector& nums) {
sort(nums.begin(), nums.end());
vector> ans;
do {
ans.push_back(nums);
} while (next_permutation(nums.begin(), nums.end()));
return ans;
}
};
此类的对象使用包含字符序列的字符串缓冲区。可以使用成员 str 将此字符序列作为字符串对象直接访问。可以使用输入和输出流上允许的任何操作从流中插入和/或提取字符。
这么说可能不太好懂,我们直接上例子⬇️
通过这一点我们可以很简单的实现输入字符串的分割操作
#include // std::string
#include // std::vector
#include // std::cout
#include // std::stringstream
using namespace std;
int main() {
stringstream ss("I am Dusong!");
vector output;
string s = "";
while (ss >> s) {
output.push_back(s);
}
for (string& s : output) {
cout << s << endl;
}
return 0;
}
继承关系
有了这样的继承关系,你可以使用所有父类的public成员函数
(详细见stringstream-C++ Referance)