[英]Find a number by given digit
假設我有一系列數字,例如:
12345678910111213141516... (until unlimited)
然后我想從給定的數字中得到一個數字。 例如:
我試圖使算法通過使用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.