持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情
题目链接:937. 重新排列日志文件
题目描述
给你一个日志数组 logs。每条日志都是以空格分隔的字串,其第一个字为字母与数字混合的 标识符 。
有两种不同类型的日志:
- 字母日志:除标识符之外,所有字均由小写字母组成
- 数字日志:除标识符之外,所有字均由数字组成 请按下述规则将日志重新排序:
- 所有 字母日志 都排在 数字日志 之前。
- 字母日志 在内容不同时,忽略标识符后,按内容字母顺序排序;在内容相同时,按标识符排序。
- 数字日志 应该保留原来的相对顺序。 返回日志的最终顺序。
提示:
logs[i]中,字与字之间都用 单个 空格分隔- 题目数据保证
logs[i]都有一个标识符,并且在标识符之后至少存在一个字
示例 1:
输入:logs = ["dig1 8 1 5 1","let1 art can","dig2 3 6","let2 own kit dig","let3 art zero"]
输出:["let1 art can","let3 art zero","let2 own kit dig","dig1 8 1 5 1","dig2 3 6"]
解释:
字母日志的内容都不同,所以顺序为 "art can", "art zero", "own kit dig" 。
数字日志保留原来的相对顺序 "dig1 8 1 5 1", "dig2 3 6" 。
示例 2:
输入:logs = ["a1 9 2 3 1","g1 act car","zo4 4 7","ab1 off key dog","a8 act zoo"]
输出:["g1 act car","a8 act zoo","ab1 off key dog","a1 9 2 3 1","zo4 4 7"]
题意整理
题目给出了一组字符串数组 logs,按照题目要求对这些字符串进行排序,最后输出排序后的结果即可。
解题思路分析
习惯性动作,观察题目数据范围为 100,数据范围较小,按照题意模拟即可。
该题难点在于理解题意上:
对于每个字符串都有一个标识符,我们以标识符后的第一个空格为分界点,将字符串分为标识符和日志两部分。日志又分为字母日志和数字日志,我们需要:
- 将所有字母日志排在所有数字日志之前;
- 将所有字母日志字符串先按照字母日志排序,如果字母日志相同,再按照标识符排序。
- 将所有数字日志按照原来的相对顺序放在所有字母日志之后;
分析完题意之后可以发现,该题就是在考察 自定义排序 和 字符串处理。
具体实现
- 首先找到标识符和日志的分界点。
- 判断当前日志是字母日志还是数字日志。
- 进行排序时分为四种情况:
- 字母日志和字母日志:我们先判断日志部分是否相同,相同的话进行标识符排序;
- 数字日志和字母日志:我们将字母日志放在数字日志之前;
- 数字日志和数字日志:按照原来的相对顺序即可,我们无需交换顺序;
- 字母日志和数字日志:字母日志应该在数字日志之前,我们无需交换顺序。
- 输出排序后的结果即可。
复杂度分析
- 时间复杂度:,其中
n为字符串数组的大小,m为字符串长度, 为排序所需的时间。 - 空间复杂度:,其中
n为字符串数组的大小,m为字符串长度,仅需存储所有字符串的空间。
代码实现
此处使用 sort 函数进行排序,自定义 sort 函数的 cmp 比较函数(也就是 sort 函数中的第三个参数),可以将 cmp 自定义函数写在外面,具体操作方法可以看 sort 函数中 cmp 的使用)。
这里使用的是 lambda 表达式 进行内置 cmp 函数(可以理解为 匿名的内联函数 ),这样的好处在于不用将需要在 cmp 中使用的外部参数修改为全局变量。 lambda 表达式会自动捕获上下文中的数据,也就是可以 直接使用外部的数据变量 。
[&](const string& log1, const string& log2)->bool{
...
}
- 这里
[&]表示引用外部的变量,也就是在该函数中对外部变量进行修改,外部变量也会跟着改变。 (const string& log1, const string& log2)这里表示传入的参数,这里将log1和log2作为常量引用,即避免了额外使用空间进行拷贝,又避免了在函数中修改该参数,这样我们就不能在函数中修改log1和log2。->bool这里表示函数的返回值类型。- 剩下的
{...}就是函数体本身了。
此外还用到了 stable_sort() 稳定排序 函数,与 sort() 函数相比,stable_sort 的用法与 sort 一致,区别是 stable_sort 函数遇到两个数相等时,不对其交换顺序;这个应用在数组里面不受影响,当函数参数传入的是结构体时,会发现两者之间的明显区别;
完整 Accept 代码
class Solution {
public:
vector<string> reorderLogFiles(vector<string>& logs) {
stable_sort(logs.begin(), logs.end(), [&](const string& log1, const string& log2)->bool{
//找到第一个空格作为分界线
int pos1 = 0;
int len1 = log1.length();
while(pos1 < len1 && log1[pos1] != ' '){
pos1++;
}
int pos2 = 0;
int len2 = log2.length();
while(pos2 < len2 && log2[pos2] != ' '){
pos2++;
}
//判断是否是字母日志
bool isLower1 = islower(log1[pos1 + 1]);
bool isLower2 = islower(log2[pos2 + 1]);
//都是字母日志
if(isLower1 && isLower2){
//截取除了标识符以外的字符
string str1 = "";
while(pos1 < len1){
str1 += log1[pos1];
pos1++;
}
string str2 = "";
while(pos2 < len2){
str2 += log2[pos2];
pos2++;
}
//先判断除标识符外的字符排序
if(str1 != str2){
return str1 < str2;
}
//再以标识符排序
else return log1 < log2;
}
//都是数字日志
if(!isLower1 && !isLower2) return false;
//一个数字日志一个字母日志,将字母日志放前面
return isLower1 ? true : false;
});
return logs;
}
};
总结
该题主要考察 自定义排序 和 字符串处理 ,其中难点在于题意理解上。
通过该题了解 lambda 表达式 的使用,通常我们还有一下几种操作:
auto check = [&]()->bool{...}:通常在写check()函数的时候可以用到,auto表示自动获取返回值类型赋给check,这里返回的是一个函数方法给check返回值类型为bool类型,之后直接调用check()即可。
还需要注意 stable_sort() 与 sort() 函数的区别,stable_sort() 是稳定排序,sort() 是不稳定排序,虽然都是快速排序,时间复杂度都为 ,区别在于稳定排序在对相同元素进行排序时不会交换其顺序,不稳定排序会交换其顺序,这个应用在数组里面不受影响,当函数参数传入的是结构体时,会发现两者之间的明显区别。
结束语
生活因劳动而变好,人生因劳动而充实。不管身处哪一个岗位,每一位劳动者的付出都值得尊重。要相信,只要坚持奋斗,平凡的我们终会闪闪发光。