5620.连续连接的二进制数字

image.png

  第一次 JS 双百,虽然是虚假的双百 😭

写法1 :耿直模拟

  使用 JS 中的进制转换函数 toStringparseInt 实现模拟。

  toString 能将十进制数字转换为任意进制数字,如 (5).toString(2) = 101

  parseInt 能将二进制数字转换为十进制数字,如 parseInt('101', 2) = 5

  不过这种写法效率可能有点差,会超时…

var concatenatedBinary = function(n) {
    let mod = 1e9 + 7;
    let sum = "";
    
    for (let i = 1; i <= n; i++) {
        sum += (i).toString(2); // 十进制转二进制然后字符串拼接
        let t = parseInt(sum, 2);   // 二进制字符串转十进制判断是否需要取余
        if (t >= mod) {
            t %= mod;
            sum = (t).toString(2);
        }
    }
    
    return parseInt(sum, 2);
};

写法2 :二进制移位模拟

  其实,我们稍微列一下二进制就能够比较直观的找到连接的规律:

  我们知道,对于二进制,每次向左移动一位就是乘上一个 2,因此若当前要连接的数字的二进制位数是两位,我们每次移动就应该乘上一个 4 ,三位二进制就乘上一个 8,移动完后末尾再加上当前的数字即可。

image.png

  若使用 JS ,需要使用 BigInt 类型,因为后面在进行移位的时候可能会过大导致算术溢出…

  如: 28399128732189371 << 1 -> -670661256

  关于 BigInt 的使用也很简单,普通数字后面加一个 n 就代表了 BigInt 类型,如 1n,或是使用构造器 BigInt(1)

  使用 BigInt 时需要注意的是 bigint 类型只能与 bigint 类型进行运算,且 Math 中的方法也不能应用在 bigint 类型上。

var concatenatedBinary = function(n) {
    let mod = BigInt(1e9 + 7);  // JS 需要使用大数,不然会溢出
    let sum = 0n;
    let p = 1n;
    let l = 2n;
    
    for (let i = 1n; i <= n; i++) {
        if (i === l) {  // 若 i 为 2 的倍数,那么移位数 + 1
            p++;
            l *= 2n;
        }
        sum <<= p;  // 累加的和每次移 p 位,然后再加上当前值
        sum += i;

        if (sum >= mod) {
            sum %= mod;
        }
    }
    
    return sum;
};

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

 目录