【问题标题】:Generate numbers in sequence Order按顺序生成数字 Order
【发布时间】:2020-01-19 05:59:50
【问题描述】:

我想生成由支票中输入的位置搜索的值。例如输入 20,该函数应该从 0 开始生成数字,并继续按升序直到生成 20 位,然后输出生成的数字串(01234567891011121314)中第 20 位的值,即 4。 我在下面尝试了这个,但是当涉及到像 1,000,000,000 这样的数字时它效率不高,

[...Array(5).keys()];  output => [0, 1, 2, 3, 4]

编辑此帖子以澄清我正在尝试获得更有效的解决方案。 在这里,我试图在一秒钟内得到长数字(1,000,000,000)的答案。

我已经有了解决方案,但需要超过 1 秒。

 [...Array(5).keys()].join("")[4]; output => 4

【问题讨论】:

    标签: javascript numbers


    【解决方案1】:

    这与Champernowne constant 几乎相同。

    math.stackexchange 的解决方案是:

    (不幸的是,Stack Overflow 不支持 MathJax)

    第一步是找出你在哪个年代。1位数字有9位,2位数字中有2⋅90=180位,一共189个,一般为n⋅9⋅10n− n个数字中的1。找到十年后,您可以从前十年中减去数字。所以如果你想要第 765 位,前 189 来自第一个和第二个十年,所以我们想要 3 位数字的第 576 位。这将出现在⌈5763⌉=第 192 个数字中,即 291。作为 576≡3(mod3),数字为 1

    以编程方式:

    const getDigit = (target) => {
      let i = 0;
      let xDigitNumbers = 1; // eg 1 digit numbers, 2 digit numbers
      let digitsSoFar = 1;
      while (true) {
        const digitsThisDecade = xDigitNumbers * 9 * 10 ** (xDigitNumbers - 1);
        if (digitsSoFar + digitsThisDecade > target) {
          // Then this is the "decade" in which the target digit is
          
          // digitIndexThisDecade: eg, starting from '100101102', to find the last '1' in '101', digitIndexThisDecade will be 6
          const digitIndexThisDecade = target - digitsSoFar;
          // numIndexThisDecade: this identifies the index of the number in the decade
          // eg, starting from '100101102', this could be index 2 to correspond to 101 (one-indexed)
          const numIndexThisDecade = Math.floor(digitIndexThisDecade / xDigitNumbers);
          // decadeStartNum: the number right before the decade starts (0, 9, 99, 999)
          const decadeStartNum = 10 ** (xDigitNumbers - 1);
          // num: the number in which the target index lies, eg 101
          const num = decadeStartNum + numIndexThisDecade;
          // digitIndexInNum: the digit index in num that the target is
          // eg, for 101, targeting the last '1' will come from a digitIndexInNum of 2 (zero-indexed)
          const digitIndexInNum = digitIndexThisDecade % xDigitNumbers;
          return String(num)[digitIndexInNum]
        }
        digitsSoFar += digitsThisDecade;
        xDigitNumbers++;
      }
    };
    
    
    
    for (let i = 0; i < 1000; i++) {
      document.write(`${i}: ${getDigit(i)}<br>`);
    }

    【讨论】:

    • 我试图让变量名不言自明,但如果这还不够清楚,我添加了一些 cmets。它只是实现链接答案中描述的算法。
    • for 循环迭代。大量迭代代价高昂 - 尝试仅记录调用结果。 console.log(getDigit(1000000000));(这样它只调用函数一次,而不是调用它并写入 HTML 数十亿次)
    【解决方案2】:

    这是一个不使用数组的简单方法。

    let N = 1000000000, digitsCount = 0, currentNumber = 0;
    console.time('Took time: ');
    const digits = (x)=>{
        if(x<10)
            return 1;
        if(x<100)
            return 2;
        if(x<1000)
            return 3;
        if(x<10000)
            return 4;
        if(x<100000)
            return 5;
        if(x<1000000)
            return 6;
        if(x<10000000)
            return 7;
        if(x<100000000)
            return 8;
        if(x<1000000000)
            return 9;
        return 10; // Default
    }
    while(true){
        digitsCount += digits(currentNumber);
        if(digitsCount >= N)
            break;
        currentNumber++;
    }
    console.timeEnd('Took time: ');
    console.log(String(currentNumber)[N-digitsCount+digits(currentNumber)-1])

    输出(执行时间可能因您而异,但会低于 1 秒(或 1000 毫秒)。)

    Took time: : 487.860ms
    9
    

    【讨论】:

    • 这仍然需要手动将currentNumber++; 从 0 迭代到所需的位数。它可能工作,但就像 OP 的实现一样,它并不是一个高效的算法(只是现代计算机可以进行 1e9 次操作)
    • 它在空间方面是一种有效的算法,因为我没有使用数组来存储数字。不过,时间复杂度仍然是O(n),并且按照问题作者的要求,对于 10^9 范围输入,它的工作时间不到 1 秒。但是,我同意在时间方面更有效的解决方案是在这里使用数学,正如您在回答中所做的那样。
    【解决方案3】:

    我使用.join("")将数组转换为字符串'01234567891011121314151617181920'

    然后通过索引字符串访问第N个数字

    N=20;
    console.log ( [...Array(N+1).keys()].join("")[N-1] )     //OUTPUT 4

    编辑:我认为有一个解决方案是你根本不需要创建数组? 这是一个数学公式

    块引用

    【讨论】:

    • 是的,它很好,但是 Array 方法效率不高,并且在处理长数字时需要更多时间。
    • 您好像忘记添加公式了?
    【解决方案4】:

    在我的解决方案中,我们不需要大的迭代和循环...... 但是这个解决方案对于简单的理解来说很重要......

    我把它做成了多达 6 位数字,而且它非常高效……并且可以做成任意位数……甚至可以简化为小函数,但这太复杂而无法理解……

    所以,给定数字的总数: 对于 1 位数字,它们是 10(0 到 9)......

    对于 2 位数,它们是 9*10 => 90 ,总位数 ==> 90*2 ==> 180...

    对于 3 位数,9*10*10 => 900 和总位数 ==> 90*3 ==> 2700...

    对于 4 位数,9*10*10*10 => 9000 和总位数 ==> 9000*4 ==> 36000...

    获取给定指定(位数)的总位数的函数

    let totalDigits = n => {
        if (n == 1) return 10;
        return 9 * (10 ** (n - 1)) * n;
    }
    

    现在,我们为不同的数字设置一个位置范围, 对于 1 Digit ,它在 1 到 10 之间....

    对于 2 位,它介于 11(1+10) 和 190(180+10) 之间...(10 中 1 的位置是 11 ,99 中的第二个 9 是 190)...

    对于 3 位数,介于 191(1+10+180) 和 2890(2700+180+10)...等等

    对于 n 位,获取 Range 的函数是

    //  This function is used to find Range for Positions... Eg : 2 digit Numbers are upto Position 190...(Position 191 is "100" first digit => 1 ) 
    let digitN = n => {
        if (n == 1) return totalDigits(1);
        return digitN(n - 1) + totalDigits(n);
    }
    
    // To Finally set Ranege for a Given Digit Number... for 1 its [1,10] , for 2 its [11,190]
    let positionRange = n => {
        if (n == 1) return [1, 10];
        else return [digitN(n - 1), digitN(n)]
    }
    

    所以最终解决方案是

    //  This Function tells the total number of digits for the given digit... Eg : there are 10 one digit Numbers , 180 Two Digit Numbers , 2700 3 Digit Numbers
    let totalDigits = n => {
        if (n == 1) return 10;
        return 9 * (10 ** (n - 1)) * n;
    }
    
    //  This function is used to find Range for Positions... Eg : 2 digit Numbers are upto Position 190...(Position 191 is "100" first digit => 1 ) 
    let digitN = n => {
        if (n == 1) return totalDigits(1);
        return digitN(n - 1) + totalDigits(n);
    }
    
    // To Finally set Ranege for a Given Digit Number... for 1 its [1,10] , for 2 its [11,190]
    let positionRange = n => {
        if (n == 1) return [1, 10];
        else return [digitN(n - 1), digitN(n)]
    }
    
    // A simple Hack to get same value for Different Consecutive Numbers , (0.3 or 0.6 or 0.9 or 1 return 1) 
    let getDigit = n => {
        if (dataType(n) == "float") {
            n = Math.floor(n);
            n++;
        }
        return n;
    }
    // To check for Float or Integer Values
    function dataType(x) {
        if (Math.round(x) === x) {
            return 'integer';
        }
        return 'float';
    }
    
    function f(position) {
    
        let result, charInd, temp;
    
        if ((position >= positionRange(1)[0]) && (position <= positionRange(1)[1])) {      //   Positions   1 to 10  (1 Digit Numbers)
            result = position - 1;
            charInd = 0
        }
        if ((position > positionRange(2)[0]) && (position <= positionRange(2)[1])) {      //   Positions   11 to 190 (2 Digit Numbers)
            temp = (position - 10) / 2;
            temp = getDigit(temp);
            result = temp + 9;
            charInd = (position - 11) % 2
        }
        if ((position > positionRange(3)[0]) && (position <= positionRange(3)[1])) {      //   Positions   191 to 2890 (3 Digit Numbers)
            temp = (position - 190) / 3;
            temp = getDigit(temp);
            result = temp + 99;
            charInd = (position - 191) % 3
        }
        if ((position > positionRange(4)[0]) && (position <= positionRange(4)[1])) {      //   Positions   2891 to 38890 (4 Digit Numbers)
            temp = (position - 2890) / 4;
            temp = getDigit(temp);
            result = temp + 999;
            charInd = (position - 2891) % 4
        }
        if ((position > positionRange(5)[0]) && (position <= positionRange(5)[1])) {      //    Positions  38890 to 488890 (5 Digit Numbers)
            temp = (position - 38890) / 5;
            temp = getDigit(temp);
            result = temp + 9999;
            charInd = (position - 38891) % 5
        }
        if ((position > positionRange(6)[0]) && (position <= positionRange(6)[1])) {      //   Positions  488890 to 5888890 (6 Digit Numbers)
            temp = (position - 488890) / 6 ;
            temp = getDigit(temp);
            result = temp + 99999;
            charInd = (position - 488891) % 6
        }
        finalChar = String(result)[charInd];
    
        console.log("Given Position => ", position, "  Result Number => ", result, "Char Index ==> ", charInd, "Final Char => ", finalChar);
    }
    let d1 = Date.now();
    f(138971); //  Given Position =>  138971   Result Number =>  30016 Char Index ==>  0 Final Char =>  3
    let d2 = Date.now();
    
    console.log(d2-d1) ;      //  351
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-21
      相关资源
      最近更新 更多