• leetcode笔记(自用)


    1024 程序员节快乐!

    匿名函数

    https://www.cnblogs.com/yaya12138/p/11815475.html

    可以放在sort的第三个参数:

    sort(a+1,a+n+1,[](node s1,node s2){return s1.ed<s2.ed;}); // 第三个参数cmp传入匿名函数
    
    • 1

    匿名函数格式:

    //[捕获列表](参数列表) -> 返回类型 {函数体}
    [](node s1,node s2) -> bool {return s1.ed<s2.ed;}
    
    // 一般情况下,编译器可以自动推断出lambda表达式的返回类型,所以我们可以不指定返回类型,如下:
    //[捕获列表](参数列表){函数体}
    [](node s1,node s2){return s1.ed<s2.ed;}
    
    // 捕获列表可以引用函数内的外部变量
    int c;
    [&c](node s1,node s2){return c;} // &是按引用传递
    [c](node s1,node s2){return c;} // 不加&就是按值传递
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    一个Lambda表达式表示一个可调用的代码单元,我们可以将它理解为一个未命名的内联函数。和任何函数类似,一个Lambda表达式具有一个返回类型,一个参数列表和一个函数体,但和普通函数不一样的是Lambda表达式可能定义在函数内部。我们可以忽略Lambda表达式的参数列表和返回类型,但不可以忽略捕获列表和函数体

    //这是正确的(忽略了参数列表和返回类型)
    //为什么没有指定返回类型还可以返回整数值?
    //因为你的函数体有return语句,它可以推断出来
    auto f = []{ return 1 + 2; };
    
    • 1
    • 2
    • 3
    • 4

    位运算

    求二进制位中1的个数。

    (1)手写

    int my_popcount(int n) {
        int cnt=0;
        while(n){
            cnt++;
            n&=(n-1);
        }
        return cnt;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这种方法比遍历n的所有二进制位数要快,n&=(n-1)一定能消除掉当前n中最低位的1。

    (2)调gcc的库

    int my_popcount(int n) {
        return __builtin_popcount(n);
    }
    
    • 1
    • 2
    • 3

    (3)std::bitset

    int my_popcount(int n) {
        bitset<31> s(n); // int范围 2^(-31)~2^(31)-1
        return s.count();
    }
    
    • 1
    • 2
    • 3
    • 4

    vector / set 的使用

    判断一个数是否在数组内,有两种方法:

    1. vector数组排序,二分查找是否在数组内。

      1. 使用**std::lower_bound()**函数,返回class类型(一般是迭代器)。

      2. 也可以用**std::binary_search()**函数,返回bool类型。

        if (std::binary_search(nums.begin(), nums.end(), val)) {...}

    2. 直接将数组放入unordered_set(内部是哈希表)。使用**std::unordered_set::count()**函数。

    STL容器的时间复杂度

    set, multiset, map, multimap内部采用的就是一种非常高效的平衡检索二叉树:红黑树

    插入/删除的时间复杂度应该是O(logn)

    cpp中set和map

    list底层是双向链表,vector底层是数组

    字符串函数

    string s;

    1、find(sub_str)
    // 如果s中找到子串sub_s
    if(s.find(sub_s)!=string::npos){
        //...
    }
    
    • 1
    • 2
    • 3
    • 4

    这个时间复杂度比较玄学,似乎是 短子串朴素暴力加一点优化+长子串two-way线性算法(参考知乎:https://www.zhihu.com/question/392846851)。猜想时间复杂度O(n)左右。最坏情况O(n*m)?

    不会手写kmp算法的时候就直接调用这个函数进行子串查找就行了。

    2、replace(first_pos, end_pos, new_sub_str)
    int pos=s.find(sub_s1); // 找到sub_s1子串的起始位置
    if(pos!=string::npos){
        // 注意sub_s1区间[first,last) 左闭右开
        s.replace(s.begin()+pos,s.begin()+pos+sub_s1.size(),sub_s2); // 将sub_s1替换为sub_s2
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    替换的复杂度应该是O(n)

    3、substr(pos, len)
    //int pos;
    // 从pos位置开始,取出长度为2的子串
    string tmp=s.substr(pos,2);
    
    • 1
    • 2
    • 3

    一定要注意第二个参数是长度!(不是结束位置)

    也可以不写第二个参数,则自动截取到末尾。

    4、stoi(str)

    即 string->int

    5、to_string(int)

    即 int->string

    左值引用、右值引用、move转换

    https://blog.csdn.net/Jacky_Feng/article/details/120742414

    (1)左值引用

    // 10只能放在等于号右边,所以10是右值;
    // num放在等于号左边,所以num是左值(不过左值也可以当成右值来使用)
    int num = 10; 
    int &b = num; //正确,左值引用初始化为左值num(这里num可以当成右值来使用)
    int &c = 10; //错误,左值引用不能初始化为右值
    
    • 1
    • 2
    • 3
    • 4
    • 5

    编译器允许我们为 num 左值建立一个引用,但不可以为 10 这个右值建立引用。

    (2)右值引用

    int num = 10;
    int && a = 10; //正确,右值引用初始化为右值10
    int && b = num; //错误,右值引用不能初始化为左值
    
    • 1
    • 2
    • 3

    修改右值引用

    int && a = 10;
    a = 11;
    cout << a << endl; //输出结果为11
    
    • 1
    • 2
    • 3

    (3)move强制转换左值为右值

    int num = 10;
    int&& a = std::move(num);
    cout << a << endl; //输出结果为10
    
    • 1
    • 2
    • 3

    C++ auto+引用

    使用auto &&[] 或者 auto&[]

    auto+两个&即可以推断出左值引用(左值引用用 “&” 表示),也可以推断出右值引用(右值引用用 “&&” 表示)

    unordered_map<string,int> mp;
    for(auto &&[sub_domain,num]:mp){
        //...
    }
    
    • 1
    • 2
    • 3
    • 4

    https://stackoverflow.com/questions/29859796/c-auto-vs-auto

    General rules for using auto are:

    • Choose auto x when you want to work with copies.
    • Choose auto &x when you want to work with original items and may modify them.
    • Choose auto const &x when you want to work with original items and will not modify them.
    • Use auto && for the ability to modify and discard values of the sequence within the loop. 使用 auto && 来修改和丢弃循环内序列的值。

    当您不关心对象是否是本地对象时,请使用 auto &&。从技术上讲,这将始终产生一个引用,但如果初始化器是临时的(例如,函数按值返回),它的行为本质上就像您自己的本地对象。

    auto && 也不保证对象是可修改的。给定一个 const 对象或引用,它将推导出 const。然而,在给定特定上下文的情况下,通常假定可修改性。(auto &&可自动推导出auto const &)

    也就是说,除非容器提供只读视图,例如 std::initializer_list,在这种情况下,它实际上是一个 auto const &。

    auto&& x = expression;
    
    • 1

    它使用引用折叠规则,与在模板代码中转发引用的情况相同。如果expression是左值,那么x是具有 cv 限定符的左值引用expression。如果expression是右值,那么x是右值引用。

    NULL与nullptr

    http://c.biancheng.net/view/7887.html

    NULL是C语言中的宏。在C++中将 NULL 定义为常量 0(#define NULL 0)。

    nullptr 是 nullptr_t 类型的右值常量,专用于初始化空类型指针。nullptr_t 是 C++11 新增加的数据类型,可称为“指针空值类型”。也就是说,nullpter 仅是该类型的一个实例对象(已经定义好,可以直接使用)。

    nullptr 可以被隐式转换成任意的指针类型。举个例子:

    int * a1 = nullptr;
    char * a2 = nullptr;
    double * a3 = nullptr;
    
    • 1
    • 2
    • 3

    不同类型的指针变量都可以使用 nullptr 来初始化,编译器分别将 nullptr 隐式转换成 int*、char* 以及 double* 指针类型。

    nullptr 可以隐式转换为指针类型,但无法隐式转换为整形。

    总之在 C++11 标准下,相比 NULL 和 0,使用 nullptr 初始化空指针可以令我们编写的程序更加健壮。

  • 相关阅读:
    Git向Gitea上传项目代码
    用HTML+CSS做一个漂亮简单的个人网页(第二篇)
    uboot默认配置过程
    【云原生 | 44】Docker搭建Registry私有仓库之管理访问权限
    回收站清空的文件能恢复吗?
    YbtOJ「基础算法」第2章 贪心算法
    2022年智慧城市行业概括及现状
    无水印免费4K视频素材网站 可商用-Free Stock Video
    Python基础复习-面向过程的编程
    Java实战-用Java mail实现Exchange发邮件给你喜欢的人
  • 原文地址:https://blog.csdn.net/ljw_study_in_CSDN/article/details/127130743