手动实现字符串方法repeat(算法优化)

动动动手动动脑才有提高!

分析: string.repeat(n) 方法会返回字符串重复值,如 let a = "abc".repeat(2),返回的是 “abcabc”。

常规方法: 采用for循环,每次累加n次初始值,则获得最终结果。

缺点:时间复杂度为o(n),有很大优化空间。这种方法简单易懂,新手都会。

优化思路:

1. 每次累加前一次的结果,如 第一次累加初始值得到 ‘abcabc’(重复2),再累加一次得到‘abcabcabcabc’(重复4),实际上就是以2的幂次方来累加,这样重复次数很大的情况下,可以明显减少累加次数

2. 我们可以找到最接近目标次数的最大幂次方,如 n = 11, 需要结果得出 repeat 11次的结果。那最接近11的2的倍数是2的3次方,然后剩余3次repeat。然后再对3继续分解为2的1次方和2的0次方。因此:

 那么:  11可以分解为 = 2的3次方 + 2的1次方 + 2 的0 次方

上代码吧!Show me the code 

方法一:通过递归逐步计算每块的值。2的3次方需要累加3次,2的1次方需要累加1次,2的0次方直接加1次。一共执行了5次,比循环11次时间复杂度缩小了一半多。

        String.prototype.myRepeat = function(num){
            let str = this.valueOf(); //初始值
            let string = ""; 
            if(num == 0) return ""  //边界条件:返回空
            if(num == 1) return str  //边界条件:返回1次
            let times = Math.floor(Math.log2(num)) //计算2为底num的对数,再取整,得到最大2次幂
            let left = num - Math.pow(2,times)  //计算剩余的需要进行多少次repeat
            for(let i = 0; i <= times; i++ ){
                if(!string){ 
                    string += str //初始值
                }else{  
                    string += string //累加
                }
            }
            let more = str.myRepeat(left)  //剩余的再执行repeat函数
            return string+more
        }
        let str = "9"
        let long = str.myRepeat(20) //repeat 20次,已优化到循环执行8次
        console.log(long)
        console.log(long.length)

缺点:执行过程从次方最大开始计算,每块会分别进行计算,计算过程有冗余。计算高次幂的同时其实已经把低次幂的计算了一次。(不推荐)

方法二:对方法一的循环进行优化(推荐),每次循环判断本次循环是否需要加上累加的str,并再对str进行翻倍累加,这样可以充分利用每次产生的2的次方倍数字符串。

1、循环条件:每次将num处以2并取整,如果num <= 0 则跳出循环;

2、每次循环判断目标字符串string 是否需要加当前的str累计倍数的值:num%2 取余,如果不为0,则本次需要加上累加值。

        String.prototype.myRepeat = function(num){
            let str = this.toString();
            let string = "";
            if(num == 0) return ""
            if(num == 1) return str
            while(num > 0){
                if(num%2 != 0){
                    string += str
                }
                num = Math.floor(num/2)
                str += str
            }
            return string
        }

 

方法三:官方源码:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/repeat 

核心算法(已去除容错判断及边界条件判断):划重点 ——  二进制  位与运算 &移位运算 >>>

String.prototype.repeat = function(count) {
    var str = '' + this;
    count = +count;
    count = Math.floor(count);
    var rpt = '';
    for (;;) {
      if ((count & 1) == 1) {  //位与运算
        rpt += str;
      }
      count >>>= 1;           //移位运算 相当于除以2取整
      if (count == 0) {
        break;
      }
      str += str;
    }
    return rpt;
  }

分析:

1. (count & 1) : count是奇数 返回 1,偶数返回0,位与运算比较 000101位与000001 返回 000001, 则为1,000110位与000001 返回000000,则为0。

2、>>> :二进制所有数位整体右移, >>> 1则为移动移位,实际效果为除以2取整,(>>>= 用法类似于 +=)

3、还是前面的原理以20为例,分解公式为  20 = 2的4次方 + 2的2次方; 

4、源码的方法比较抽象,太高级了(实际执行循环次数为4次,比第一种方案再提升了一倍效率)
  执行 rpt += str的时候,str每次循环之后翻倍(str+=str),如果第一次循环执行到这句,实际效果是rpt(初始值为“”)加上2的0次方(str的上次累加值,初始值为this),第n次循环循环执行到这句的时候,实际效果rpt加2的n次方。

官方方法简便效率很高。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值