面试撕leetcode环节的C++ STL常用用法总结(下)

本篇文章讲讲面试过程中C++手撕leetcode环节多数人使用C++做题的高频易错地方,本质上是由于对C++不熟悉而导致的python和C++语法混用。本文首发于我的公众号“AI不止算法”,文章链接在此

为什么要总结STL常用用法

对STL容器、算法、迭代器等的使用在C++类工作的面试撕题中基本跑不掉,这很容易看出一个候选人的coding能力,同时日常工作中也会经常使用,可以达到简化某些逻辑的目的,上篇也已经简单介绍过动机,本文接着上篇继续总结本人认为经常用到的一些STL用法,更加侧重于算法函数,同时也作为自己的一个复习笔记~

算法

常用的算法基本都位于头文件中

填充类:

  • fill(begin, end, v):填充某容器的值全为v,源码如下,非常简单有趣,把迭代器和值模板化,这样就使得fill可以应用在任意容器和任意类型的scalar
template< class ForwardIt, class T >
void fill(ForwardIt first, ForwardIt last, const T& value)
{
    for (; first != last; ++first) {
        *first = value;
    }
}
//用法也比较简单
std::vector<int> a;
std::fill(a.begin(),a.end(),6);
  • generate(begin, end, func)/generate_n(begin, n, func) :使用func生成数据填充到某容器的begin到end或者前n个位置中,比如以下根据斐波那契数列规则填充10个元素到vector,这个我个人感觉貌似用的不多,当然可能是我个人用的少的原因
class Fibonacci{
    int f1;
    int f2;
public:
    Fibonacci(int start1, int start2){
        f1 = start1;
        f2 = start2;
    }
    int operator()(){
        int r = f1 + f2;
        f1 = f2;
        f2 = r;
        return r;
    }
};
int main(){
    vector<int> v1(10);
    generate(v1.begin(), v1.end(), Fibonacci(0, 1));
}

generate/generate_n的源码也很有趣,很好理解,把迭代器和生成器通过模板泛化,这样就使得generate可以应用在任意容器和任意函数

template <class ForwardIterator, class Generator>
  void generate ( ForwardIterator first, ForwardIterator last, Generator gen )
{
  while (first != last) {
    *first = gen();
    ++first;
  }
}

template <class ForwardIterator, class Generator>
  void generate_n ( ForwardIterator first, size n, Generator gen )
{
  while (n>0) {
    *first = gen();
    ++first; --n;
  }
}

变换类

  • transform

我自己是非常喜欢用transform函数,因为非常简洁省事,支持unary和binary操作,并且支持inplace,当我们想要对某个容器做某种修改操作时,这可以替代掉很多繁重的for循环,先看看源码声明,上面是unary操作时的写法,下面是binary操作时的写法,意思是对first1到last1的所有元素做unary op操作,或者对两个input的所有元素做binary op操作,通过fill和generate的源码,我们大致可以猜出transform的源码:

template <class InputIterator, class OutputIterator, class UnaryOperation>
  OutputIterator transform (InputIterator first1, InputIterator last1,
                            OutputIterator result, UnaryOperation op){
    while (first1 != last1) {
        *d_first++ = unary_op(*first1++);
    }
    return d_first;
}  
  
template <class InputIterator1, class InputIterator2,
          class OutputIterator, class BinaryOperation>
  OutputIterator transform (InputIterator1 first1, InputIterator1 last1,
                            InputIterator2 first2, OutputIterator result,
                            BinaryOperation binary_op){
 
    while (first1 != last1) {
        *d_first++ = binary_op(*first1++, *first2++);
    }
    return d_first;
}

来几个例子感受一下

//uanry例子:把每个字符都大写,并且大写后的结果原地保存在s
std::string s("Hello");
std::transform(s.begin(), s.end(), s.begin(),
    [](unsigned char c) { return std::toupper(c); });
std::cout << s << std::endl; // HELLO


// binary例子:把foo和bar两个vector相加结果保存在foo,结果为5个3
std::vector<int> foo(5, 1);
std::vector<int> bar(5, 2);
// std::plus adds together its two arguments:
std::transform(foo.begin(), foo.end(), bar.begin(), foo.begin(), std::plus<int>());

区间最大最小值

  • 签名:max_element/min_element(iterator1/address, iterator2/address)

  • 返回值:iterator或地址,加上解引用*即得最大最小值

  • 优点:当我们要求某个区间范围内的最大最小值或者最大最小值的index时, max_element和min_element直接传入这个区间的起始地址即可,会比循环max/min方便很多,尤其是数组是多维的时候。比如leetcode 120题的官方解法就用到了

  • 例子:

int a[] = {1, 2, 3, 4};
int maxPosition = max_element(a,a + 2) - a; //最大值下标
int max_val = *max_element(a,a + 2); //最大值
vector<int> n = {1, 2, 3, 4};
int maxPosition = max_element(n.begin(), n.end()) - n.begin(); //最大值下标
int max_val = *max_element(n.begin(), n.end());//最大值

复制函数

  • 签名:copy(iterator1, iterator2, dst_iterator)

  • 类似函数:copy和memcpy都是copy,但是他们的最大区别是memcpy是byte by byte的copy,而copy是ele by ele的copy,我们很多时候可能更多的是想做后者,但是却用成了前者,这也是很多memcpy相关bug的发生地

  • 例子:把a的三个元素从temp的首地址一直copy

std::vector<int> temp(3);  
int a[3] = {1, 2, 3};  
std::copy(a, a+3, &temp.front());

总结

还有非常多有用的算法函数没有列出,总的来说,从以上的叙述可以看出,都符合一个规律:他们都可以很方便地对某个区间或者范围做某种操作,只需要指定起始地址和结束地址,并且传入相应的value或者function去操作就好了。

最后,欢迎关注我的公众号“AI不止算法”。

  • 21
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值