Generate numbers in sequence Order

时光毁灭记忆、已成空白 提交于 2020-06-08 19:05:10

问题


I want to generate the value being searched by the position entered in the check. For example, if 20 is entered, the function should generate numbers starting from 0 and continue in ascending order until 20 digits are created, then output the value of the 20th digit in the generated number string (01234567891011121314), which is 4. I tried this below, however it is not efficient when it comes to numbers like 1,000,000,000,

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

Edit this post to clarify I am trying to get a more efficient solution. Here I am trying to get the answer for long numbers(1,000,000,000) in below one second.

I already have a solution but it takes more than 1 second.

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

回答1:


This is nearly identical to the Champernowne constant.

A solution from math.stackexchange is:

(Stack Overflow doesn't support MathJax, unfortunately)

The first step is to find what decade you are in. There are 9 digits from the 1 digit numbers, 2⋅90=180 digits from the 2 digit numbers for a total of 189, and generally n⋅9⋅10n−1 from the n digit numbers. Once you have found the decade, you can subtract the digits from the earlier decades. So if you want the 765th digit, the first 189 come from the first and second decades, so we want the 576th digit of the 3 digit numbers. This will come in the ⌈5763⌉=192nd number, which is 291. As 576≡3(mod3), the digit is 1

Programatically:

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>`);
}



回答2:


Here's a simple approach without using arrays.

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])

Output (The execution time may differ for you but it'll be under 1 second(or 1000ms).)

Took time: : 487.860ms
9



回答3:


i used .join("") to convert the array to string '01234567891011121314151617181920'

then access the Nth number by Indexing string

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

EDIT:i think ther's a solution which is you don't need to create array at all😎 its a mathematical formula

Blockquote




回答4:


In my Solution , we don't need big iterations and loops... But This Solution is Big for simple understanding...

I made it for upto 6 digits , and its very efficient...and can be made for any number of digits... And can even be reduced to small functions , but that would get too complex to understand...

So , Total numbers for Given Digits : For 1 Digit Numbers , They are 10 (0 to 9)....

For 2 Digit Numbers , They are 9*10 => 90 , and total Digits ==> 90*2 ==> 180...

For 3 Digit Numbers , 9*10*10 => 900 , and total Digits ==> 90*3 ==> 2700...

For 4 Digit Numbers , 9*10*10*10 => 9000 , and total Digits ==> 9000*4 ==> 36000...

A function to get Total Digits for a given specified (Number of Digits)

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

Now , we set a Range of position for different Digits , for 1 Digit , its between 1 and 10....

for 2 Digits , It's Between 11(1+10) and 190(180+10)...(position of 1 in 10 is 11 , and Second 9 in 99 is 190)...

for 3 Digits , It's Between 191(1+10+180) and 2890(2700+180+10)...And so on

for n Digit , Function to get Range is

//  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)]
}

So Final Solution is

//  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


来源:https://stackoverflow.com/questions/59807561/generate-numbers-in-sequence-order

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!