• Related to the third param of function “sort“ & Lambda of Cpp


    1.前置题目:

    1331.数组序号转换
    1408. 数组中的字符串匹配

    1.1.两道简单题,但分别对应了,两种不同的情况,即引出:

    • (单次排序后通过不改变原数组顺序得到其角标按照数组排序规律的数组)与lambda表达式的引出。

    与1408的字符串与数组的搭配限制和传统实现:

    • 由于第一个数组类型是vector而不是vector,即遍历所用元素不对应,即简单的lambda表达式不再适用。

    1.2 关于lambda表达式

    I:用处

    就用一次的简易函数?

    II:构造

    [caoture] (params) opt -> ret {body;};
    
    • 1
    • [] 不捕获任何变量
    • [&] 捕获外部作用域中所有变量,并作为引用在函数体中使用(按引用捕获)
    • [=] 捕获外部作用域中所有变量,并作为副本在函数体中使用(按值捕获)
    • [=,&foo] 按值捕获外部作用域中所有变量,并按引用获取foo变量
    • [bar] 按值捕获bar变量,同时不捕获其他变量
    • [this] 捕获当前类中的this指针,让lambda表达式拥有和当前类成员同样的访问权限,如果已经使用了&或者=,就默认添加此选项,捕获this的目的是可以在lambda中使用当前类的成员函数和成员变量
      总而言之,"[]"里面放的就是需要在body作用域内部用到的,想要在body内用的就在这里取一下。

    3、简单的lambda表达式(cpp)

    [r = arr.data()](int a, int b){return r[a] < r[b];}
    
    • 1

    2.实例分析

    2.1—leetcode_1331

    code

    class Solution {
    public:
        vector<int> arrayRankTransform(vector<int>& arr) {
            vector<int> idx(arr.size());
            iota(idx.begin(), idx.end(), 0);
            sort(idx.begin(), idx.end(), [r = arr.data()](int a, int b){return r[a] < r[b];});
            //取到指针会更快
            int rk = 0, rear = INT_MIN;
            for(int x: idx){
                if(arr[x] != rear) ++rk;
                rear = arr[x];
                arr[x] = rk;
            }
            return arr;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    比较重要的地方就是sort的第三个参数,即lambda表达式。这道题由于要按照排序arr的方式排序其下标数组idx,即lambda表达式作为函数代替了传统的比较函数。且两个数组之间的联系都用int型变量,因此可以直接进行调用,arr的排序方法,作用于idx(sort前两个参数决定)。

    • 这里有一个小tips,由于"[]"取到的是在body里面用的数据,就猜想了一下是不是直接传arr而不是arr的头指针进去也可以呢?经过尝试发现结果是可行的,但是由于传入的是对象,即使经过自动判断r也是一个arr的对象,这样实例化对象次数太多会大大占用系统的空间并增加运行时间。
    • 那么再思考,是否直接取到对象的引用就可以了呢?答案是纯纯的老瘫儿,因为 “&arr” 和 “arr.data()”是一个东西。本质上其实都是数组。

    但若出现容器装着不同类型的数据呢?这样直接的方法是否依然适用?答案是否。引出1408:

    2.2—leetcode_1408

    code-错误尝试

    class Solution {
    public:
        vector<string> stringMatching(vector<string>& words) {
            int wordsSize = words.size();
            vector<string>result;
            vector<int>everySize;
            for (size_t i = 0; i < wordsSize; i++)
            {
                everySize.push_back(words[i].size());
            }//初始化一波size数组为自定义bool base
            sort(words.begin(), words.end(), [r = everySize.data()](int a,int b){return r[a] < r[b];});
            //lamba表达式,sort的第三参,字符串数组的排序
            for (size_t i = 0; i < wordsSize; i++)
            {
                for (size_t j = i+1; j < wordsSize; j++)            {
                    if(words[j].find(words[i]) != string::npos){
                        result.emplace_back(words[i]);
                        break;
                    }
                }
            }
            return result;
        }
    };
    // @lc code=end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    显然,我想通过对其对应字符串长度的排序方式来排序words,但是很遗憾,由于lambda表达式的局限性,入参是两个int的情况下是无法直接对应装着 string 的数组的(cmp函数不匹配)。那么要是直接写cmp函数的方式该如何实现呢?这里问了身边的同事:

    bool cmp(const std::string &a, const std::string &b){
        if (a.size() != b.size()){
            return a.size() < b.size();
        } else/* 考虑到两者size相等的情况 */{
            return a < b;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    经过测试后,排序是成功的,那么写成lambda形式呢?

    [](string &str1,string &str2){
    	if (str1.size() != str2.size()){
            return str1.size() < str2.size();
        	} else/* 考虑到两者size相等的情况 */{
            	return str1 < str2;
        	}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    感觉和上面的bool-cmp没啥不一样,只是自动生成了函数返回值和名。。。。蚌埠了。
    最后,挂个官方的暴力法题解吧:

    class Solution {
    public:
        vector<string> stringMatching(vector<string>& words) {
            vector<string> ret;
            for (int i = 0; i < words.size(); i++) {
                for (int j = 0; j < words.size(); j++) {
                    if (i != j && words[j].find(words[i]) != string::npos) {
                        ret.push_back(words[i]);
                        break;
                    }
                }
            }
            return ret;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    其中也有需要注意的点,即找字符串的子字符串的方法:words[j].find(words[i]) != string::npos

    .

    3、总结

    1、想通过排序A的方式排序B,要是想使用lambda表达式的形式,那AB的入参形式一定要一样。
    2、想通过模仿1131的形式,来通过建立字符串长度数组(对应角标是其大小对应的字符串)后,再对字符串数组进行排序,且想要其排序方式按照长度数组排序顺序的想法固然是是好的,但利用lambda表达式的形式并不ok,因为入参不一样,两个string和两个int并无法对应,系统无法识别。建议使用传统cmp或不简洁的lambda表达式。

    思考

    1、那通过将其长度作为主键利用map数据结构进行排序呢?啊,map不允许key重复啊,要保持映射唯一性。
    2、映射不可以轻易建造捏,因为不管是string,还是长度都有可能重复。

    anyway,最后的解决方法就是像上面的总结说的,同参用lambda简单,不同参要是可以直接调其对象属性的情况下,还是写一个cmp吧。

  • 相关阅读:
    数学建模--K-means聚类的Python实现
    编译OpenSycl报错Cannot run simple program using std::filesystem
    SpringMVC获得请求数据类型
    【C语言】转圈报数问题(三种方法--指针,数组)
    鸿蒙Harmony应用开发—ArkTS声明式开发(通用属性:尺寸设置)
    Ansible+Shell+Containerd部署k8s
    Python入门教程 - 基本语法 (一)
    图解 Google V8 # 18 :异步编程(一):V8是如何实现微任务的?
    Exception | ShardingSphere | ShardingSphere引发的IndexOutOfBoundsException
    利用已存在的conda环境
  • 原文地址:https://blog.csdn.net/qq_42645708/article/details/126194688