一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第17天,点击查看活动详情。
本题难度:
时间复杂度为 O(n):⭐ ⭐
时间复杂度为 O(logn):⭐ ⭐ ⭐
本题类型:算法、手写
padStart 函数其实平时用得不是很多,但是以前 JS 没有这个 API 的时候,很多人是引的一个叫 left-pad 的包,但是这个包发生过一些事件,感兴趣的朋友们可以看一下下面的链接。
NPM 与 left-pad 事件:我们是不是早已忘记该如何好好地编程?
其实很多时候,一些简单的功能我们都可以自己封装一个函数实现,根本没必要引三方包,尽可能地避免上面的事件发生。
padStart 用法
padStart()
方法用另一个字符串填充当前字符串(如果需要的话,会重复多次),以便产生的字符串达到给定的长度。从当前字符串的左侧开始填充。
const str = 'hello'
console.log(str.padStart(10, '.')) // '.....hello'
实现
方式1
一层循环搞定。
function padStart(str, length, char) {
let res = ''
let len = length - str.length
for (let i = 0; i < len; i++) {
res += char
}
return res + str
}
方式2
转数组再 join。
function padStart(str, length, char) {
return Array(length - str.length + 1).join(char) + str
}
方式3
方式1和方式2时间复杂度都是 O(n),其实可以用二分法来进一步优化效率,把时间复杂度优化到 O(logn)。
/**
* 二分的思想来拼接字符串
*
* 假设需要拼接的长度为 len ,要拼接的字符 char 是 'x'
*
* 对 len 二分,每次操作 len = parseInt(len / 2)
* 每次操作 char 翻倍,char += char,就不用一个一个拼接了
*
* 'x'
* 'xx'
* 'xxxx'
* 'xxxxxxxx'
*
* 拼接字符串的时间复杂度从 O(n) 降到 O(lgn)
*
* 当 len = 1 时,说明已经是最小单位了,就可以返回了
* 假设 len = 7,最终要返回的结果为 total
*
* 遇到奇数的情况,也就是 len % 2 === 1 时,total += char
*
* 初始化 total '' char x len 7
* 第一次操作 total x char xx len parseInt(7 / 2) = 3
* 第二次操作 total xxx char xxxx len parseInt(3 / 2) = 1
* 第三次操作 total xxxxxxx
*
* 都是偶数的情况,假设 len = 4,就是下面这种
*
* 第一次操作 total '' char xx len parseInt(4 / 2) = 2
* 第二次操作 total '' char xxxx len parseInt(2 / 2) = 1
* 第三次操作 total xxxx
*
*/
function padStart3(str, length, char) {
let len = Math.floor(length) - str.length
if (len < 1) {
return str
}
let total = ''
while(true) {
if (len % 2 === 1) {
total += char
}
if (len === 1) {
return total + str
}
len = parseInt(len / 2)
char += char
}
}
时间复杂度: O(lgn)
最后,可以继续优化,用位运算稍微改进一下
不懂位运算的可以参考我的这篇文章:为了看懂 Vue3 diff算法,我学习了JS 位运算
/**
* 位运算改进
* len % 2 === 1 也就是 len & 1
* parseInt(len / 2) 也就是 len >> 1
*/
function padStart(str, length, char) {
let len = Math.floor(length) - str.length
if (len < 1) {
return str
}
let total = ''
while(true) {
if (len & 1) {
total += char
}
if (len === 1) {
return total + str
}
len = len >> 1
char += char
}
}
测试一下性能:
console.log('循环 10000 次')
console.time('直接拼接')
for(let i = 0; i< 10000; i++) {
padStart1(str, 10000, '.')
}
console.timeEnd('直接拼接')
console.time('二分法')
for(let i = 0; i< 10000; i++) {
padStart2(str, 10000, '.')
}
console.timeEnd('二分法')
console.time('二分法 + 位运算')
for(let i = 0; i< 10000; i++) {
padStart3(str, 10000, '.')
}
console.timeEnd('二分法 + 位运算')
可以看出,二分法真的极大的优化了性能。
普通查找(线性时间):O(n)
二分查找(对数时间):O(logn)
在包含 100 个数字的列表中查找,二分查找最多只需 7 次。
在包含 40 亿个数字的列表中查找,二分查找最多只需 32 次。
数据量越大,二分查找带来的性能提升越大。
结尾
阿林水平有限,文中如果有错误或表达不当的地方,非常欢迎在评论区指出,感谢~
如果我的文章对你有帮助,你的👍就是对我的最大支持^_^
你也可以关注《前端每日一问》这个专栏,防止失联哦~
我是阿林,输出洞见技术,再会!
上一篇:
下一篇: