⌈C++⌋accumlate、__builtin_、next_permutation等各类用于解算法题的库函数与类模板(持续更新中~)

目录

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

持续更新中......


1.accumulate

①求和:

第三个参数作为初始值,将区间[first, end)的值相加,返回初始值加上区间总和的值。

需要注意的是,如果总和超出区间中数的类型范围,可以将第三个参数强转成64位的long long类型

#include <iostream>    
#include <numeric>      // std::accumulate
#include <vector>       

int main() {
	int init = 0;
	std::vector<int> 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 <iostream>    
#include <numeric>      // std::accumulate
#include <vector>

template<class T>
class myclass {
public:
	int operator()(T x, T y) { return x + 3 * y; }
};

int main() {
	int init = 0;
	std::vector<int> 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<int>());
	//output: 0 + 100 * 3 + 200 * 3 + 300 * 3 = 1800
	return 0;
}

2.__builtin_ctz / __builtin_ctzll

__builtin系列的函数为GCC编译器的内联函数;

__builtin_ctz用于计算一个32位数中后导零的数量

cout << __builtin_ctz(16);  //16: 10000 --->  output:4

 __builtin_ctzll用于计算一个64位数中后导零的数量

cout << __builtin_ctzll(1LL << 40);   //output: 40

3.__builtin_clz / __builtin_clzll

__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位数前导零数量

3.__builtin_popcount

用于计算一个数的二进制中1的个数

cout << __builtin_popcount(15);   //output: 4

4.bitset

bitset类模拟了存放bool类型的array ,但是对其做了空间优化,每个元素0或1都只占用了一个位,并且可以用 [ ] 访问每一位的值

4.1 参数

4.2 构造函数

#include <iostream>
#include <bitset>
#include <string>
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的应用

① 快速擦找大量数据是否在一个集合总

② 求两个集合的交集

③操作系统中的磁盘块标记

④排序去重

5.lower_bound / upper_bound

C++标准库自带的二分查找算法,对于lower_bound(val),函数返回 [first, last) 范围内val下限(第一个大于等于val)位置的迭代器,而upper_bound则是返回 [first, last) 范围内val上限(第一个大于val)位置的迭代器

#include <iostream>     // std::cout
#include <algorithm>    // std::lower_bound, std::upper_bound, std::sort
#include <vector>       // std::vector

int main() {
	int myints[] = { 10,20,30,30,20,10,10,20 };
	std::vector<int> 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<int>::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

6.min_element / max_element

返回区间 [first, last) 中最小值的迭代器

// min_element/max_element example
#include <iostream>     // std::cout
#include <algorithm>    // std::min_element, std::max_element
#include <vector>
int main() {
	std::vector<int> 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;
}

7.iota

见文章【C++】iota函数 + sort函数实现基于一个数组的多数组对应下标绑定排序_Dusong_的博客-CSDN博客


8. next_permutation

按字典序的到全排类的下一个排列,如果函数可以将对象重新排列为字典上更大的排列,则返回 true。否则,该函数返回 false 以指示排列不大于前一个排列

#include <iostream>     
#include <algorithm>    
#include <vector>
using namespace std;
int main() {
    vector<int> 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<vector<int>> permute(vector<int>& nums) {
        int n = nums.size();
        vector<vector<int>> ans;
        vector<int> path(n), vis(n, false);
        function<void(int)> 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<vector<int>> permute(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> ans;
        do {
            ans.push_back(nums);
        } while (next_permutation(nums.begin(), nums.end()));
        return ans;
    }
};

9.  stringstream

此类的对象使用包含字符序列的字符串缓冲区。可以使用成员 str 将此字符序列作为字符串对象直接访问。可以使用输入和输出流上允许的任何操作从流中插入和/或提取字符。

这么说可能不太好懂,我们直接上例子⬇️

通过这一点我们可以很简单的实现输入字符串的分割操作

#include <string>       // std::string
#include <vector>       // std::vector
#include <iostream>     // std::cout
#include <sstream>      // std::stringstream
using namespace std;

int main() {
	stringstream ss("I am Dusong!");
	vector<string> output;
	string s = "";
	while (ss >> s) {
		output.push_back(s);
	}
	for (string& s : output) {
		cout << s << endl;
	}
	return 0;
}

 输出:

继承关系

 有了这样的继承关系,你可以使用所有父类的public成员函数

(详细见stringstream-C++ Referance

10 int/long/long long 与 string 之间的转换

#include <cstdlib>   //std::stoi	std::stol	std::stoll
#include <string>   //std::to_string()

int main() {
	int type_int = 1;
	long type_long = 1;
	long long type_longlong = 1;
	std::string s_int = std::to_string(type_int);   //int -> string
	std::string s_long = std::to_string(type_long);    //long -> string
	std::string s_longlong = std::to_string(type_longlong);    //long long -> string

	std::string num = "1234567";
	int a = stoi(num);    //string -> int
	long b = stol(num);    //string -> long
	long long c = stoll(num);    //string -> long long
}

持续更新中......​​​​​​​

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dusong_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值