https://leetcode-cn.com/problems/sort-the-jumbled-numbers/
好好的一道重排序,结果看到一个天秀之子在秀c++语法
属实有点秀了,特打算做个笔记
5217. 将杂乱无章的数字排序
给你一个下标从 0 开始的整数数组 mapping
,它表示一个十进制数的映射规则,mapping[i] = j
表示这个规则下将数位 i
映射为数位 j
。
一个整数 映射后的值 为将原数字每一个数位 i
(0 <= i <= 9
)映射为 mapping[i]
。
另外给你一个整数数组 nums
,请你将数组 nums
中每个数按照它们映射后对应数字非递减顺序排序后返回。
注意:
nums
中的元素只有在排序的时候需要按照映射后的值进行比较,返回的值应该是输入的元素本身。示例 1:
输入:mapping = [8,9,4,0,2,1,3,5,7,6], nums = [991,338,38] 输出:[338,38,991] 解释: 将数字 991 按照如下规则映射: 1. mapping[9] = 6 ,所有数位 9 都会变成 6 。 2. mapping[1] = 9 ,所有数位 1 都会变成 8 。 所以,991 映射的值为 669 。 338 映射为 007 ,去掉前导 0 后得到 7 。 38 映射为 07 ,去掉前导 0 后得到 7 。 由于 338 和 38 映射后的值相同,所以它们的前后顺序保留原数组中的相对位置关系,338 在 38 的前面。 所以,排序后的数组为 [338,38,991] 。
示例 2:
输入:mapping = [0,1,2,3,4,5,6,7,8,9], nums = [789,456,123] 输出:[123,456,789] 解释:789 映射为 789 ,456 映射为 456 ,123 映射为 123 。所以排序后数组为 [123,456,789] 。
提示:
mapping.length == 10
0 <= mapping[i] <= 9
mapping[i]
的值 互不相同 。1 <= nums.length <= 3 * 104
0 <= nums[i] < 109
上菜
下面进行相关知识补充
和 sort() 函数一样,实现 stable_sort() 的函数模板也位于
头文件中,因此在使用该函数前,程序也应包含如下语句:
#include
并且,table_sort() 函数的用法也有 2 种,其语法格式和 sort() 函数完全相同(仅函数名不同):
//对 [first, last) 区域内的元素做默认的升序排序
void stable_sort ( RandomAccessIterator first, RandomAccessIterator last );
//按照指定的 comp 排序规则,对 [first, last) 区域内的元素进行排序
void stable_sort ( RandomAccessIterator first, RandomAccessIterator last, Compare comp );
其中,first 和 last 都为随机访问迭代器,它们的组合 [first, last) 用来指定要排序的目标区域;另外在第 2 种格式中,comp 可以是 C++ STL 标准库提供的排序规则(比如 std::greater
举个例子:
#include // std::cout
#include // std::stable_sort
#include // std::vector
//以普通函数的方式实现自定义排序规则
bool mycomp(int i, int j) {
return (i < j);
}
//以函数对象的方式实现自定义排序规则
class mycomp2 {
public:
bool operator() (int i, int j) {
return (i < j);
}
};
int main() {
std::vector myvector{ 32, 71, 12, 45, 26, 80, 53, 33 };
//调用第一种语法格式,对 32、71、12、45 进行排序
std::stable_sort(myvector.begin(), myvector.begin() + 4); //(12 32 45 71) 26 80 53 33
//调用第二种语法格式,利用STL标准库提供的其它比较规则(比如 greater)进行排序
std::stable_sort(myvector.begin(), myvector.begin() + 4, std::greater()); //(71 45 32 12) 26 80 53 33
//调用第二种语法格式,通过自定义比较规则进行排序,这里也可以换成 mycomp2()
std::stable_sort(myvector.begin(), myvector.end(), mycomp);//12 26 32 33 45 53 71 80
//输出 myvector 容器中的元素
for (std::vector::iterator it = myvector.begin(); it != myvector.end(); ++it) {
std::cout << *it << ' ';
}
return 0;
}
程序执行结果为:
12 26 32 33 45 53 71 80
那么,stable_sort() 函数的效率怎么样呢?当可用空间足够的情况下,该函数的时间复杂度可达到O(N*log2(N))
;反之,时间复杂度为O(N*log2(N)2)
,其中 N 为指定区域 [first, last) 中 last 和 first 的距离。
transform
算法transform()提供以下两种能力:
1.第一形式有4个参数,把源区间的元素转换到目标区间。也就是说,复制和修改元素一气呵成;
2.第二形式有5个参数,将前两个源序列中的元素合并,并将结果写入目标区间。
注意:含有修改元素,仅仅只做复制元素,可以使用copy()。
第一种形式
transform(sourceBeg,sourceEnd,destBeg,op)
(1)针对源区间[sourceBeg,sourceEnd)中的每一个元素调用:op(elem) 并将结果写到以destBeg起始的目标区间内;
(2)返回目标区间内“最后一个被转换元素”的下一个位置,也就是第一个未被覆盖的元素位置;
(3)调用者必须确保目标区间有足够的空间,要不就得使用插入型迭代器;
(4)sourceBeg于destBeg可以相同,所以,和for_each()算法一样,你可以使用这个算法来变动某一序列内的元素;
(5)如果想以某值替换符合某一准则的元素,应使用replace()算法;
(6)复杂度:线性;
代码示例(第一种形式):
#include"fuzhu.h"
using namespace std;
int main()
{
vector coll1;
list coll2;
INSERT_ELEMENTS(coll1,1,9);
PRINT_ELEMENTS(coll1,"coll1: ");
transform(coll1.begin(),coll1.end(),coll1.begin(),negate());
PRINT_ELEMENTS(coll1,"negated: ");
transform(coll1.begin(),coll1.end(),back_inserter(coll2),bind2nd(multiplies(),10));
PRINT_ELEMENTS(coll2,"coll2: ");
transform(coll2.rbegin(),coll2.rend(),ostream_iterator(cout," "),negate());
cout<
运行结果:
coll1:1 2 3 4 5 6 7 8 9
negated: -1 -2 -3 -4 -5 -6 -7 -8 -9
coll2: -10 -20 -30 -40 -50 -60 -70 -80 -90
90 80 70 60 50 40 30 20 10
第二种形式
transform(source1Beg,source1End,source2Beg,destBeg,op)
(1)针对第一源区间[source1Beg,source1End)以及“从source2Beg开始的第二源区间”的对应元素,调用:op(source1Elem,source2Elem) 并将结果写入以destBeg起始的目标区间内;
(2)返回区间内的“最后一个被转换元素”的下一位置,就是第一个未被覆盖的元素的位置;
(3)调用者必须保证第二源区间有足够空间(至少拥有和第一区间相同的空间大小);
(4)调用者必须确保目标区间有足够空间,要不就得使用插入型迭代器;
(5)source1Beg,source2Beg,destBeg可以相同。所以,可以让元素自己和自己结合,然后将结果覆盖至某个序列;
(6)复杂度:线性;
代码示例:
#include"fuzhu.h"
using namespace std;
int main()
{
vector coll1;
list coll2;
INSERT_ELEMENTS(coll1,1,9);
PRINT_ELEMENTS(coll1,"coll1: ");
transform(coll1.begin(),coll1.end(),coll1.begin(),coll1.begin(),multiplies());//1*1 2*2
PRINT_ELEMENTS(coll1,"squared: ");
transform(coll1.begin(),coll1.end(),coll1.rbegin(),back_inserter(coll2),plus());//1+81 4+64
PRINT_ELEMENTS(coll2,"coll2: ");
cout<<"diff: ";
transform(coll1.begin(),coll1.end(),coll2.begin(),ostream_iterator(cout," "),minus());//1-82 4-68
cout<
运行结果:
coll1:1 2 3 4 5 6 7 8 9
squared: 1 4 9 16 25 36 49 64 81
coll2: 82 68 58 52 50 52 58 68 82
diff: -81 -64 -49 -36 -25 -16 -9 -4 -1
C++11的新特性,匿名函数(Lambda)
auto:当编译器能够在一个变量的声明时候就推断出它的类型,那么你就能够用auto关键字来作为他们的类型
例如这样
vector vec;
vector::iterator itr = vec.iterator();
变成这样
vector vec;
auto itr = vec.iterator();
然后是 新的返回语法,后置了…
由这样
Person::PersonType Person::getPersonType ()
{
return _person_type;
}
变成这样
auto Person::getPersonType () -> PersonType
{
return _person_type;
}
还有 类型获取(Decltype)
int x = 3;
decltype(x) y = x; // same thing as auto y = x;
看上去都是一些简单的卖弄技巧的东西啊,不过他们组合起来就变成酱紫:
template
auto
makeAndProcessObject (const Builder& builder) -> decltype( builder.makeObject() )
{
auto val = builder.makeObject();
// do stuff with val
return val;
}
这样就为代码带来很大的方便了,尤其是lambda中。
以前看python的时候,对lambda的理解是:如果一个函数只在某一小块地方被调用,其它地方不用的话,用lambda表达式会增加可读性以及减少代码量吧。
lambda的形式是:
[captures] (params) -> ret {Statments;}
captures的选项有这些:
[] 不截取任何变量
[&] 截取外部作用域中所有变量,并作为引用在函数体中使用
[=] 截取外部作用域中所有变量,并拷贝一份在函数体中使用
[=, &foo] 截取外部作用域中所有变量,并拷贝一份在函数体中使用,但是对foo变量使用引用
[bar] 截取bar变量并且拷贝一份在函数体重使用,同时不截取其他变量
[this] 截取当前类中的this指针。如果已经使用了&或者=就默认添加此选项。
都是关于怎么使用外部变量的。
最简单的例子,就像这样:
[] () -> int { return 1; }
分析一下最上面的例子吧。
// Declare graph of factor types and build the factor structure
std::vector priors;
float tree_ms = ts::timing_ms([&]() {undefined
graph = InitFactorGraph(forest, priors, dags_train, sigma_unary, sigma_pw,
levels_unary, levels_pw, feat_box_max, feat_radius);
});
std::cout << "Decision tree induction took " << (tree_ms/1000.0) << "s" << std::endl;
首先ts::timing_ms是一个模板函数返回float:
// Execute 'func', and return the duration of the function call, in ms.
template inline float timing_ms(Func func)
{
return timing_median_ms(1, func);
}
timing_ms 调用了 timing_median_ms,再调用func 得到float返回值。 这个func实际上就是lambda表达式了。表达式用到 [&],说明它能够以引用形式使用其他的外部变量,因为里面的一些参数,如graph,是一个外部变量 。
这样兜兜转转,实际上对功能更好地划分了吧。把实际要做的事放在lambda里,时间计数放在timing_ms封装好的地方。
记忆化可加可不加,不加不要用to_string,会被卡常
class Solution {
public:
vector sortJumbled(vector& mapping, vector& nums) {
stable_sort(begin(nums), end(nums), [trs = [&](auto x){
int ret = 0, e = 1;
do{
ret += mapping[x%10]*e;
x /= 10;
e *= 10;
}while(x);
return ret;
}](auto x, auto y){ return trs(x) < trs(y); });
return nums;
}
};
#尊重作者的成果
作者:MuriyaTensei
链接:https://leetcode-cn.com/problems/sort-the-jumbled-numbers/solution/c-zi-ding-yi-pai-xu-stlyi-ju-quan-zhi-xi-4eiv/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
vector sortJumbled(vector& mapping, vector& nums) {
int n = nums.size();
vector t(n), d(n);
iota(d.begin(), d.end(), 0);
transform(nums.begin(), nums.end(), t.begin(), [&](auto x){
int ret = 0, e = 1;
do{
ret += mapping[x%10]*e;
x /= 10;
e *= 10;
}while(x);
return ret;
});
stable_sort(begin(d), end(d), [&](auto x, auto y){
return t[x] < t[y];
});
for(int& x: d) x = nums[x];
return d;
}
};
作者:MuriyaTensei
链接:https://leetcode-cn.com/problems/sort-the-jumbled-numbers/solution/c-zi-ding-yi-pai-xu-stlyi-ju-quan-zhi-xi-4eiv/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
这里用到了c++ 11 的新特性lamda匿名函数,我看了好久才吸收这部分精华
吸收知识后的代码
class Solution {
public:
vector sortJumbled(vector& mapping, vector& nums) {
unordered_map mp;
for (auto num : nums){
int ret = 0, mul = 1, temp = num;
do{
ret += mapping[temp % 10] * mul;
temp /= 10;
mul *= 10;
}while(temp);
mp[num] = ret;
}
stable_sort(nums.begin(), nums.end(), [&](auto a, auto b){
return mp[a] < mp[b];
});
return nums;
}
};
参考博客:
C++标准库---transform()_lanzh_-CSDN博客_c++ transform
c++11 匿名函数[] [this] [&] [=]_超超大爷的博客-CSDN博客_[&]