簡體   English   中英

按給定數字查找數字

[英]Find a number by given digit

假設我有一系列數字,例如:

12345678910111213141516... (until unlimited)

然后我想從給定的數字中得到一個數字。 例如:

  • 第10位: 1
  • 第17位: 3
  • ...

我試圖使算法通過使用PHP來實現,但是如果我給出的給定位數超過10.000.000 ,由於我進行的循環超出了內存大小,它總是向我顯示錯誤。 Allowed Memory Size of 134217728 Bytes Exhausted

我該如何處理而不必修改php.ini文件的memory_limit

以下是我試圖弄清楚該算法的方法:我對本機可以處理的循環的最大值進行了基准測試,發現它是10.000.000 ,然后我假定如果需要,則需要制作一個單獨的循環給定的數字/參數大於10.000.000。 但是最后我仍然遇到內存不足的錯誤。 真的很感謝。

<?php

/*
* benchmark result: 
* max digit = 10.000.000
*/

$benchmarkedDigit = 10000000;
$digit = 1000000000000; // it could be dynamically assigned, i.e. a parameter. In this case will show an error since the given digit is 10 trillion

$s = '';
if ($digit > $benchmarkedDigit) {
    $mod = fmod($digit, $benchmarkedDigit);
    $div = $digit / $benchmarkedDigit;

    for ($x = 1; $x <= $div; $x++) {
        $upperLimit = ($x * $benchmarkedDigit);

        for ($y = ($upperLimit - $benchmarkedDigit + 1); $y <= $upperLimit; $y++) {
            $s .= $y;
        }

        // so it could be:
        // 1 - 10.000.000
        // 10.000.001 - 20.000.000
        // 20.000.001 - 30.000.000
        // ...
    }

    // loop for the rest of the fmod(), if its result is not 0
    for ($i = ($upperLimit + 1); $i <= ($upperLimit + $mod); $i++) {
        $s .= $i;
    }
} else {
    for ($x = 1; $x <= $digit; $x++) {
        $s .= $x;
    }
}

echo substr($s, ($digit - 1), 1);

您可以使用這樣的事實,即總是有10^n - 10^(n-1)個n位長數字(甚至1位,因為我看到0不在這里)。

有了這些知識,您就可以跳過大量的數字。 您從n = 1開始,並檢查n位數字的數量是否低於所需的數字。 如果是這樣,則從所需的數量減少n位數字的數量,將n增加1並重新開始。

例如:您想知道該數字中的第512位數字1位數字(10)的數量是否比所需的數字(512)低? 是的,因此所需的數字應減少那么多(512-9)。 2位數字的數量(90)是否低於所需的數字(現在為503)? 是的,因此所需的位數應減少那么多(503-90)。 3位數字的數量(900)是否低於所需的數字(現在為413)? 否,因此所需的數字是3位數的數字之一。 413/3是137(向下舍入),因此它是第137個3位數的數字之一(即237)。 413%3(模)為2,所以它是第二個數字,所以應該是3。

可能會有錯誤的計算,但是總體邏輯應該不會太遠。

編輯 :您也可以使用生成器,但這可以增加大數的運行時間

function getNthDigit() {
    for ($i = 0;; ++$i) { // Start with 0, which is the 0-th digit
        foreach (str_split((string)$i) as $digit) {
            yield $digit;
        }
    }
}

$desiredDigit = 512;
foreach (getNthDigit() as $number => $digit) {
    if ($number == $desiredDigit) {
        break;
    }
}
// $digit should be the desired digit
<?php

function getDigit($Nth){

    if($Nth < 10) return $Nth;

    $no_of_digits = 1;
    $current_contribution = 9;
    $actual_length = 9;
    $prev_length = 0;
    $starting_number = 1;


    $power_of_10 = 1;

    while($actual_length < $Nth){
        $no_of_digits++;
        $current_contribution *= 10;
        $prev_length = $actual_length;
        $actual_length += ($current_contribution * $no_of_digits);
        $power_of_10 *= 10;
        $starting_number *= 10;
    }

    $Nth = $Nth - $prev_length;
    $offset = $Nth % $no_of_digits === 0 ? intval($Nth / $no_of_digits) - 1 : intval($Nth / $no_of_digits);

    $number = strval($starting_number + $offset);

    for($i=1;$i<=$no_of_digits;++$i){
        if(($Nth - $i) % $no_of_digits === 0){
            return $number[$i-1];
        }
    }
}

// first 100 Digits 
for($i=1;$i<=100;++$i){
    echo getDigit($i),PHP_EOL;
}

演示: https //3v4l.org/3l0I7

算法:

要找到第n 數字,我們將首先找到數字,然后選擇該數字的哪個數字作為答案。

查找號碼:

  • 如果我們仔細觀察,該序列將按順序增加,如表中所示。

表:

| Digits| Total numbers(of current digit)| Total Digits | Total digits of whole string  |
|-------|--------------------------------|--------------|-------------------------------|
| 1     | 9                              | 9            | 9                             |
| 2     | 90                             | 180          | 189                           |
| 3     | 900                            | 2700         | 2889                          |
| 4     | 9000                           | 36000        | 38889                         |
  • 上表顯示我們,如果我們想找到,讓我們說 500位,那么它的3位數字的一些數字。 如果我們輸入 17 數字,則是2位數字的某個數字,依此類推。

  • 現在,以 200位為例。 由於它小於2889且大於189 ,所以它來自3位數字。

  • 我們要做的是將200分解為較小的數字,例如200 - 189 = 11 11表示它是某個3位數字的第11位數字,該數字以3位數字的起始數字100開頭( 3位數字的起始數字)。

  • 現在,我們進行11 / 3 (其中3是位數),並將商得到3 3意味着它3過去起始編號100 ,我們可以說作為100 + 3 = 103 (因為它是100101102,然后將第四酮,為103)。

  • 現在,我們知道數字是103 剩下的就是找出103哪一位。

  • 請注意,有時我們遇到偶數除法的極端情況,例如12 /3。在這種情況下,我們從商中減去1,因為我們的3位數系列從100開始,而不是101(以此類推,對於其他數位依此類推,依此類推)。

找出數字:

  • 現在,我們知道第200位數字是103 (也就是我們上面計算的11 )。 為了找出哪一個,我們依次記下3位數字並仔細觀察它們。

序列:

1 0 0 1 0 1 1 0 2 1  0  3  1  0  4  1  0  5  1  0  6

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
  • 如果您觀察到,您可以理解最高的MSB數字遵循序列1,4,7,10,13等。第二高的MSB遵循序列2,5,8,11,14等,最后一個MSB(是LSB)遵循3、6、9、12、15等的順序。

  • 因此,從上述序列來看,很明顯, 11 (我們最初將200分解后得到)屬於MSB數字第二大的序列。

  • 因此,來自103的最終答案是0 (從左數第二位)。

$num = '12345678910111213141516';

echo $num[16];

結果: 3

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM