简单介绍一下我解这两道题的思路和误区,最后附上正确代码!
(一)先看下题目(懒得打了)
这题的规律挺好找的,第一行(a1)有一个,第二行(a2)有两个,~~~,第n行(an)有n个,于是,前n行(Sn)有(n*n+n)/2个。假如$line(即要查找的那个整数)在第n+1行,则可以用$line-Sn来表示该数在这一行(an+1)的位置。下面我们来找一下每一行(an)的规律,取一个长一点的行 a33=123456789876543212345678987654321,我们可以很容易的看出这段数字可以被分成若干个”2345678987654321“拼接起来的,那么我们就可以用($line-Sn)%16来代表目标数字在字符串中的位置,上面就是这一题的思路。下面是我的第一种方法(本地环境):
//方法1 运行超时
($n*$n+$n)/2&&$res<=($n*$n+3*$n+2)/2){
$b=$res-($n*$n+$n)/2;
break;
}
}
$c=$b%16;
var_dump($a,$b,$c,$a[$c]);
代码超级简单,但是当$line长度大于15时,代码执行开始变得缓慢,长度大于17时,已经开始超时,不符合小米OJ的要求。
唔,回头重读题目,突然发现他的运行空间有点大———10M。回头再看我们的代码,发现我们获取Sn的循环的次数特别多,于是,我们可以用空间来换取时间:
//方法2 运行成功
3){
for($n=2;;$n++){
$s[$n]=$n+$s[$n-1];
$s[$n+1]=$n+1+$s[$n];
if($line>$s[$n]&&$line<=$s[$n+1]){
$b=$line-$s[$n];
break;
}
}
$c=$b%16;
}
// 返回处理后的结果
// return $ans;
echo $a[$c];
代码复杂了一点,实际上是因为多了一个if判断,本地运行时有可能会报”致命错误“,其实仔细看后面可以发现是因为本地默认的空间不够,这个可以设置,传到线上就能正常执行。下面粘上正确代码:
function solution($line) {
// 在此处理单行数据
$a=["2","1","2","3","4","5","6","7","8","9","8","7","6","5","4","3"];
$b=1;
$s[1]=1;
$s[2]=3;
if($line<=3){
if($line==3){
$c=2;
}else{
$c=1;
}
}elseif($line>3){
for($n=2;;$n++){
$s[$n]=$n+$s[$n-1];
$s[$n+1]=$n+1+$s[$n];
if($line>$s[$n]&&$line<=$s[$n+1]){
$b=$line-$s[$n];
break;
}
}
$c=$b%16;
}
// 返回处理后的结果
// return $ans;
return $a[$c];
}
(二)老规矩,先看题目
这一题相对而言难了很多,因为an的规律没那么好找了,不过,如果仔细一点的话还是能找到的:我们发现,当n>9时,数字开始变成了两位,公差变成了2,当n>99时,数字变成了三位,公差变成了3,~~~,这样我们可以在循环时将n的长度获取到,来作为公差,于是,$w=strlen($n),an=w*n-((10^w-10)/9-w+1),看上去有点复杂,但运用高中的知识可以很轻松的算出来。还是找到$line在an中的位置,将an用1,2,~~~,99,100,~~~拼接起来,变成字符串,然后获取数字,(快下班了不多说了^~^),直接粘代码:
//找到第N个数字ii
function solution($line) {
$an = 0;
for($n=1;$n<=$line;$n++){
$w=strlen($n);
$bn = $w*$n-((pow(10,$w)-10)/9-$w+1);
$an+=$bn;
$an_1=$an-$bn;
if($an>=$line&&$an_1<$line){
$x = $line-$an_1;
$y = '';
for($i=1;$i<=$x+2;$i++){
$y .=$i;
$len = strlen($y);
if($len>$x){
$res = substr($y,$x-1,1);
return $res;
}
}
}
}
}
如有错误,欢迎各位大佬指正!