LeetCode 记录-791. 自定义字符串排序
我的解法
思路
我的思路是计数。先用 order 生成一个字符-数组的 map 用来存 s 中出现的字符,同时在 map 中也添加了一个 "other" key,用来存 order 中不存在的字符。遍历一边 s,将 s 中的字符添加到对应的数组中。最后,拼接数组形成一个字符串并返回。
代码
/**
* @param {string} order
* @param {string} s
* @return {string}
*/
var customSortString = function (order, s) {
const orderMap = new Map([]);
for (let c of order) {
orderMap.set(c, []);
}
orderMap.set("other", []);
for (let c of s) {
if (orderMap.has(c)) {
orderMap.get(c).push(c);
} else {
orderMap.get("other").push(c);
}
}
return [...orderMap.values()].map((orderItem) => orderItem.join("")).join("");
};
复杂度分析(自我分析,不一定对)
时间复杂度
,n 为 s 的长度,k 为 order 的长度。
空间复杂度
,k 为 order 的长度,以 order 为基础建立 map 所需要的空间代价的期望是。n 为 s 的长度,因为在 map 每个 value 的数组中存了出现的字符,数组总的大小为 s 的长度。
官方解法 1: 自定义排序
思路
通过 order 生成一个权值表,然后用这个权值表对 s 进行排序。
权值表的生成思路如下:
遍历给定的字符串 order,将第一个出现的字符的权值赋值为 1,第二个出现的字符的权值赋值为 2,以此类推。所有未出现的字符的权值为 0。
代码
// 官方解法1: 自定义排序-理解思路后我写的解法
/**
* @param {string} order
* @param {string} s
* @return {string}
*/
var customSortString = function (order, s) {
const val = new Array(26).fill(0);
for (let i = 0; i < order.length; i++) {
val[order[i].charCodeAt() - "a".charCodeAt()] = i + 1;
}
const sArr = [...s];
sArr.sort(
(c0, c1) =>
val[c0.charCodeAt() - "a".charCodeAt()] -
val[c1.charCodeAt() - "a".charCodeAt()]
);
return sArr.join("");
};
// 官方解法1: 自定义排序-官方代码
/**
* @param {string} order
* @param {string} s
* @return {string}
*/
var customSortString = function (order, s) {
const val = new Array(26).fill(0);
for (let i = 0; i < order.length; ++i) {
val[order[i].charCodeAt() - "a".charCodeAt()] = i + 1;
}
const arr = new Array(s.length).fill(0).map((_, i) => s[i]);
arr.sort(
(c0, c1) =>
val[c0.charCodeAt() - "a".charCodeAt()] -
val[c1.charCodeAt() - "a".charCodeAt()]
);
let ans = "";
for (let i = 0; i < s.length; ++i) {
ans += arr[i];
}
return ans;
};
可以看到上面有两个函数,一个是我理解官方思路后自己写的,一个是直接 copy 的官方代码。有意思的是,它们逻辑看起来是差不多的(应该说是一模一样),但是最终的时间消耗差距蛮大,第一种我写的耗时 80ms,击败 9.57%。第二种则耗时 64ms,击败 60%。这两种写法区别在于从字符串生成数组以及将数组合并为字符串,官方的写法虽然看起来比较复杂,但是耗时很少。
复杂度分析
时间复杂度
,其中 是字符串 的长度, 是字符集,在本题中 。
- 排序的时间复杂度为 ;
- 如果我们使用数组储存权值,数组的大小为;如果我们使用哈希表储存权值,哈希表的大小与字符串 s 和 order 中出现的字符种类数相同,为叙述方便也可以记为 。
空间复杂度
,即为数组或者哈希表需要使用的空间。
官方解法 2: 计数排序
思路
和我的思路类似,就不详细介绍啦。
代码
var customSortString = function (order, s) {
const freq = new Array(26).fill(0);
for (let i = 0; i < s.length; ++i) {
const ch = s[i];
++freq[ch.charCodeAt() - "a".charCodeAt()];
}
let ans = "";
for (let i = 0; i < order.length; ++i) {
const ch = order[i];
while (freq[ch.charCodeAt() - "a".charCodeAt()] > 0) {
ans += ch;
freq[ch.charCodeAt() - "a".charCodeAt()]--;
}
}
for (let i = 0; i < 26; ++i) {
while (freq[i] > 0) {
ans += String.fromCharCode(i + "a".charCodeAt());
freq[i]--;
}
}
return ans;
};
复杂度分析
时间复杂度
,其中 是字符串 的长度, 是字符集,在本题中 。
空间复杂度
,即为数组或者哈希表需要使用的空间。