1.前置题目:
1331.数组序号转换
1408. 数组中的字符串匹配
/>>>>>>>>>>>>>>>>>>>>>>>下面是后添加的例子
2418. 按身高排序
1.1.两道简单题,但分别对应了,两种不同的情况,即引出:
- (单次排序后通过不改变原数组顺序得到其角标按照数组排序规律的数组)与lambda表达式的引出。
与1408的字符串与数组的搭配限制和传统实现:
- 由于第一个数组类型是vector而不是vector,即遍历所用元素不对应,即简单的lambda表达式不再适用。
1.2 关于lambda表达式
I:用处
就用一次的简易函数?
II:构造
[caoture] (params) opt -> ret {body;};
- [] 不捕获任何变量
- [&] 捕获外部作用域中所有变量,并作为引用在函数体中使用(按引用捕获)
- [=] 捕获外部作用域中所有变量,并作为副本在函数体中使用(按值捕获)
- [=,&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];}
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;
}
};
比较重要的地方就是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
显然,我想通过对其对应字符串长度的排序方式来排序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;
}
}
经过测试后,排序是成功的,那么写成lambda形式呢?
[](string &str1,string &str2){
if (str1.size() != str2.size()){
return str1.size() < str2.size();
} else/* 考虑到两者size相等的情况 */{
return str1 < str2;
}
}
感觉和上面的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;
}
};
其中也有需要注意的点,即找字符串的子字符串的方法:words[j].find(words[i]) != string::npos
2.3—leetcode_2418.
code—错误尝试
class Solution {
public:
vector<string> sortPeople(vector<string>& names, vector<int>& heights) {
unordered_map<string, int>mp;
for (int i = 0; i < names.size(); ++i) {
mp.emplace(names[i],i);
}
sort(names.begin(), names.end() ,[&](const string &a, const string &b){
return heights[mp[a]] > heights[mp[b]];
});
return names;
}
};
- 很明显我想通过建立int和string之间的关系,因为通过身高排序名字直接用lamda表达式是不可行的。就算我建立了名字到下标的映射,想直接用名字对应的高度拿下排序,用例中存在两个bob,真阴呐,名字无法单个映射到固定下标,可恶。
- 尽管提示中没有出现相同的身高,不过在现实生活中还是身高重复更频繁一点,因此这道题还是要考虑的多一点。
code—题解
class Solution {
public:
vector<string> sortPeople(vector<string>& names, vector<int>& heights) {
int n = (int)names.size();
int idxs[n];
for (int i = 0; i < n; i ++){
idxs[i] = i;
}
sort(idxs, idxs + n, [&](const int & i, const int & j){
return heights[i] > heights[j];
});
vector<string> res;
for (int i: idxs){
res.push_back(names[i]);
}
return res;
}
};
作者:XingHe_XingHe
- 思路是初始化下标数组(只用数组存储下标用来接收按高度排序后下标的变化)
- 根据指定的下标读取名字,按个push到结果数组内
- 妙,我是傻逼
3、总结
1、想通过排序A的方式排序B,要是想使用lambda表达式的形式,那AB的入参形式一定要一样。
2、想通过模仿1131的形式,来通过建立字符串长度数组(对应角标是其大小对应的字符串)后,再对字符串数组进行排序,且想要其排序方式按照长度数组排序顺序的想法固然是是好的,但利用lambda表达式的形式并不ok,因为入参不一样,两个string和两个int并无法对应,系统无法识别。建议使用传统cmp或不简洁的lambda表达式。
3、第三题用了下标数组接收了变化,直接用unordered_map接收的方式无法cover重复名字或重复身高的情况,即双向不符合函数的映射性质。接收数组变化就完美适配了捏!如果要按照字典序就另说,差不多完美了。
思考
1、那通过将其长度作为主键利用map数据结构进行排序呢?啊,map不允许key重复啊,要保持映射唯一性。
2、映射不可以轻易建造捏,因为不管是string,还是长度都有可能重复。
3、加了中间层接收身高排序,结果用下标读name数组,那是真的牛批。
anyway,最后的解决方法就是像上面的总结说的,同参用lambda简单,不同参要是可以直接调其对象属性的情况下,还是写一个cmp吧。遇到无法正确映射或者双向映射都重复的时候,就想一想增加一个中间层!