n的最后一个非零数字!


22

给定整数1≤N≤1,000,000作为输入,输出N的最后一个非零数字哪里是阶乘(从1N的所有数字的乘积)。这是OEIS序列A008904

您的程序需要在合理的机器上10秒钟内完成任何有效输入。

测试用例

1 => 1
2 => 2
3 => 6
4 => 4
5 => 2
6 => 2
7 => 4
8 => 2
9 => 8
10 => 8
100 => 4
1000 => 2
10000 => 8
100000 => 6
1000000 => 4

这是一个因此以字节为单位的最短代码胜出!


单一功能还是完整程序?
乔伊,

@joey不,它们只是测试用例。单输入单输出。
fR0DDY 2011年

@joey完整程序。
fR0DDY 2011年

1
不鼓励要求参加完整的课程...
Egg the Outgolfer

2
@EriktheOutgolfer这来自大约7年前,所以我认为当时还没有确定
NoOneIsHere18年

Answers:


8

红宝石-63个字符

f=->n{n<2?1:6*[1,1,2,6,4,4,4,8,4,6][n%10]*3**(n/5%4)*f[n/5]%10}

来源-http://oeis.org/A008904

一秒钟内处理f到一千个数字。

测试

irb(main):014:0> for n in 2..6
irb(main):015:1> puts f[10**n]
irb(main):016:1> end
4
2
8
6
4

11

Mathematica,45 36字节

Last@Select[IntegerDigits[#!],#>0&]&

可读性强的答案。:)(然后,再次没有GolfScript&Co.提交。)

这样可以在大约5秒钟内在我的计算机上处​​理1,000,000个输入。


1
Mathematica几乎是这个问题的完美语言。
Michael Stern

4

巨蟒-75

n=input()
g=1
while n:
 g*=n
 while g%10<1:g/=10
 g%=10**9
 n-=1
print g%10

3

PARI / GP-27个字节

这以速度为代价-测试用例需要很长时间(〜6秒)。

n->n!/10^valuation(n!,5)%10

这个版本更快(〜15微秒),但占用81个字节:

n->r=1;while(n,r*=Mod(4,10)^(n\10%2)*[1,2,6,4,2,2,4,2,8][max(n%10,1)];n\=5);lift(r)

您可以使用以下(非高尔夫)代码来测试以下任何一项:

[%(10^n) | n <- [1..6]]

2

Windows PowerShell,53 56 59 60 63 73 90

($a=1).."$input"|%{$a="$($a*$_)".trim('0')%1e7}
$a%10

笔记:

  • 花费超过一分钟的时间才能获得接近100,000的数字。但是,最后删除零需要转换为字符串,计算需要数字,因此在任何情况下转换都是不可避免的。

历史:

  • 2011-02-08 10:31(90)–第一次尝试。
  • 2011-02-08 10:33(73)–模量比切片和连接短。
  • 2011-02-08 10:34(63)–不必要的修剪。
  • 2011-02-08 10:37(60)–不必要地转换为数字。Modulus已经做到了。
  • 2011-02-08 10:40(59)–一些内联。
  • 2011-02-08 11:00(56)–关于模数缩短,我之前怎么说?同样适用于输出。
  • 2011-02-08 11:01(53)–转换$input为字符串就足够了;强制转换int为隐式应用。

2

Perl,53岁 58 61 人物

可以删除所有空格,但出于“可读性”的考虑,我将其保留。注意:不要使用Sloane的一些愚蠢的明确公式。

sub f {
    $_ = $1 * ++$n || 1, /(.{1,7}?)0*$/ while $n < $_[0];
    $1 % 10
}

在我的计算机上,在8.7秒内计算f(10 ^ 6)。

更新:OP希望它成为一个完整的程序:

$_ = $1 * ++$n || 1, /(.{1,7}?)0*$/ while $n < $ARGV[0];
print $1 % 10

这使它成为55个字符。


2

果酱-28

1ri{I)*_AbW%{}#A\#/1e7%}fIA%

您可以在http://cjam.aditsu.net/上尝试将其设置为10000左右的值。对于更大的数字,您应该使用java解释器。1000000在我的笔记本电脑上运行约3秒钟。

说明:

不幸的是,直接的解决方案太慢了,因此每次乘法后,我只保留最后7位数字(在尾随零之前)。

1           push 1 on the stack
ri          read a token and convert to integer
{           loop (for I from 0 to N - 1)
    I)      push I and increment
    *       multiply with the previous value (initially 1)
    _Ab     duplicate and convert to array of digits
    W%      reverse array
    {}#     find the position of the first non-zero digit
    A\#     raise 10 to that power
    /       divide, thus removing all trailing zeros
    1e7%    keep the remainder modulo 10000000
}fI         end for loop
A%          get the last digit

注意:这种语言比问题要新得多。



2

05AB1E,4个字节

!0м¤

在线尝试!

说明

!0    # Push the factorial of the input and 0
  м   # Remove the occurences of 0 in the factorial
   ¤  # Push the last element, implicit display

1
TIO版本在最后一个测试用例上超时(60s)-您如何在“合理的机器”上的10s内获得它?
Toby Speight '18

2

果冻,4字节

!Ṛȯ/

在线尝试!

说明

使用以下事实:将(反向列表;不向量化)应用于整数时,它将首先自动取D(数字)。

使用输入8:

!Ṛȯ/
!     Factorial: 8! = 40320
 Ṛ    Reverse: [0,2,3,0,4]
   /  Reduce by...
  ȯ   ...logical OR: ((((0ȯ2)ȯ3)ȯ0)ȯ4) = first truthy element = 2

我认为不存在一个字节的“第一个真实元素”(它ȯ/充当),但是如果存在,则可以将其缩短为三个字节。


2

Java(OpenJDK 8),62字节

n->{long f=n;for(;n>1||f%10==0;)f=n>1?f*--n:f/10;return f%10;}

在线尝试!

与@Kevin Cruijssen相似,但通过组合循环可节省5个字节。


欢迎来到PPCG!不错的第一篇文章!希望你坚持!
Rɪᴋᴇʀ

欢迎来到PPCG!我同意@Riker的精彩第一篇文章。通过组合循环,可以很好地了解我的代码。您可以通过替换||为当前答案中|的另外1个字节,并替换==0<1。入住愉快!
凯文·克鲁伊森

2

C,150个 140 135字节

r,d;f(k,x){r=x<5?3:f(k+1,x/5);return(d=x%5)?r*"33436"[d]*(1<<d*k%4)%5:r;}main(int c,char**v){c=atoi(*++v);printf("%d",c<2?1:2*f(0,c));}

这是ASCII系统的版本;替换字符串3343611214用于EBCDIC系统,或具有\1\1\2\1\4用于可移植程序。

C解决方案因提供完整程序的要求而受阻。但是,这确实可以完全回答问题。

在线尝试(需要Javascript):

说明

它基于n!的最低有效非零数字中概述的算法,然后转身,以便我们递归以找到5的最高幂,然后在出路时进行计算。常数表太大,因此我通过找到前一个残差r,当前数字d和递归深度之间的关系来简化它们k

     0    1       2       3    4  =d
  0  0  3×2^k  1×2^2k  3×2^3k  2
  1  1  1×2^k  2×2^2k  1×2^3k  4
r 2  2  2×2^k  4×2^2k  2×2^3k  3
  3  3  3×2^k  3×2^2k  3×2^3k  2
  4  4  4×2^k  4×2^2k  4×2^3k  1

对于r>0,它解析为恒定的r倍数2^dk(mod 5);常量在a[]下面(在高尔夫球代码中内联)。我们还观察到它(2^4)%5是1,因此我们可以减小指数以避免溢出范围int

const int a[] = { 1, 1, 2, 1, 4 };
int f(int k, int x){
    int r = x<5 ? 3 : f(k+1,x/5); /* residue - from recursing to higher-order quinary digits */
    int d = x%5;
    if (!d)
        return r;
    return r * a[d] * (1<<d*k%4) % 5;
}

int main(int c, char **v)
{
    c = atoi(*++v);
    printf("%d",
           c<2
           ? 1                  /* special-case 0 & 1 */
           : 2*f(0,c));         /* otherwise, it's 2 times r */
}

测试:

$ for i in 100 1000 10000 100000; do echo $i: `./694 $i`; done
100: 4
1000: 2
10000: 8
100000: 6
1000000: 4

性能也很出色。这是32位系统的最大输入int

$ time ./694 2147483647
8
real    0m0.001s
user    0m0.000s
sys     0m0.000s

我也使用最大64位进行了相同的计时int


1
可能有意思的是,它2147483647!有超过190亿个数字和(2^63-1)!超过170,000,000,000,000,000,000个数字,因此这在计算阶乘上是一个很大的胜利。 1000000!问题中指定的在当前硬件上进行计算是可行的;只有5千5百万个数字。:-)
Toby Speight,2016年

1

PHP-105

 <?foreach(explode("\n",`cat`)as$n)if($n){$f=rtrim(gmp_strval(gmp_fact($n)),'0');echo substr($f,-1)."\n";}

用给定的测试用例在10秒内运行。


1

Python3

239个字符

可以在约3.2秒内完成10000次(Ideone在8秒时切断了我的权限,但我敢肯定它会花费10秒以上的时间,尽管:()

from functools import *
N=100
r=range
s=(p for p in r(2,N)if all(p%n>0for n in r(2,p)))
f=lambda n,x:n//x+(n//x>0and f(n//x,x)or 0)
e=list([p,f(N,p)]for p in s)
e[0][1]-=e[2][1]
e[2][1]=0
print(reduce(lambda x,y:x*y,map(lambda x:x[0]**x[1],e))%10)

Python2.6

299个字符(快一点)

from itertools import *
N=100000
r=xrange
def s(c=count(2)):
        while 1:p=c.next();c=ifilter(p.__rmod__,c);yield p
f=lambda n,x:n//x+(n//x>0and f(n//x,x)or 0)
e=[[p,f(N,p)]for p in takewhile(lambda x:x<N,s())]
e[0][1]-=e[2][1]
e[2][1]=0
print(reduce(lambda x,y:x*y,map(lambda x:pow(x[0],x[1],10),e))%10)


1

J – 42 40个字符

整个程序。将此程序保存到文件中并运行jconsole script.ijs 1234。请注意,该程序在打印结果后不会退出解释器。输入^Dexit]0退出解释器。

echo([:{:@(#~*)10&#.inv@*)/1+i.".>{:ARGV

这里是一个解释:

  • x #. y将整数向量解释y为基数x;例如,10 #. 1 2 3 4yields 1234
  • u inv产生动词的u。特别是,x #. inv y表示y为基数x;例如,10 #. 1234yields 1 2 3 4。请注意,inv定义为^:_1,即u应用-1次。
  • x * y产品xy,从而x 10&#.inv@* y得到的产物的碱-10表示xy
  • x # y拷贝Ñ的第项y经常作为Ñ的第项x; when x是布尔向量,x选择y要取的项。例如, 1 0 1 0 # 1 2 3 4yields 1 3
  • * y产生的正负号y
  • x u~ y自反性u,也就是说,相同的y u x
  • 因此,y #~ * y得出所有y正项的向量。用默认符号可以用钩子表示(#~ *)
  • {: y产生中的最后一项y
  • 组装在一起,我们得到了默认的短语([:{:@(#~*)10&#.inv@*)
  • u/ y减少y,即,二元动词u的元件之间插入y。例如,+/1 2 3 4like 1 + 2 + 3 + 4和yields 10
  • 因此,该短语([:{:@(#~*)10&#.inv@*)/ y产生的项的乘积的最后一位数字y
  • ARGV 是命令行参数的框式向量。
  • ".>{:ARGV 是开箱并解释为数字的最后一个参数。
  • i. y计算从0到的自然数y - 1
  • 因此,1+i. y产生从1到的自然数y。我也可以 在这里使用>: 增量,但是1+在相同的字符成本下更加清晰。
  • 整个程序仅将动词(最后一个命令行参数中数字1+i.".>{:ARGV的向量1)应用于动词,([:{:@(#~*)10&#.inv@*)/并使用输出结果echo

1

Pyt,5 个字节

!₫ą0⦋

说明:

         Implicit input (n)
!        n!
 ₫       Reverse the digits of (n!) - this disregards leading zeroes after reversal
  ą      Convert to array of digits
   0⦋    Get the first element

在线尝试!


1

R63 55 51 46字节

计算阶乘,提取最后一个非零数字。感谢Giuseppe提供的基本结构。

(y=(gamma(scan()+1))%/%10^(0:1e5)%%10)[!!y][1]

在线尝试!

或者,我以前的51字节答案:

计算阶乘,转换为字符,删除所有0s,然后获取最终字符。感谢Giuseppe,节省了2个字节。

substring(x<-gsub("0","",gamma(scan())+1),nchar(x))

在线尝试!


1
gamma(x+1)短于factorial(x)
Giuseppe

没有字符串转换,我设法得到的最好是(y=(x<-gamma(scan()+1))%/%10^(0:nchar(x))%%10)[!!y][1]54个字节。
朱塞佩

@Giuseppe我们可以更换nchar(x)1e5一个46字节的解决方案!太好了
rturnbull


1

Perl 6的 26  35个字节

{[*](1..$_)~~/.*<(<-[0]>/}

试试吧


作为完整程序:

put [*](1..@*ARGS[0])~~/.*<(<-[0]>/

试试吧

展开:

{
  [*]( 1..$_ ) # reduce using &infix:« * »
  ~~           # match with
  /
    .*         # any number of values (so it matches from the end)
    <(         # only capture the following
    <-[0]>     # any value but 0 (negated character class)
  /
}

1

C(gcc),72个字节(函数)

f(n,d)long long n,d;{for(d=1;n;d%=10000)for(d*=n--;d%10<1;d/=10);d%=10;}

在线尝试!

C(gcc)101 99字节(整个程序)

main(){long long n,d=1;for(scanf("%lld",&n);n;d%=10000)for(d*=n--;d%10<1;d/=10);printf("%d",d%10);}

在线尝试!

这个问题只有8年的历史了,因此“合理的机器”与当时不一样,但是当一起处理所有测试用例时,我的计算机上的时间仅为〜.01秒,因此除非计算机速度提高在最近十年中,将其放大1000倍就可以了。


摩尔定律仍然保持(稳定),因此它应该快大约16倍
仅ASCII的

另外,函数也很好
仅限ASCII


0

附件,26字节

Last@`\&:(All@V)@Digits@`!

在线尝试!

说明

Last@`\&:(All@V)@Digits@`!

这是4个功能的组合:

  • `! -这是阶乘运算符的功能版本
  • Digits -这得到阶乘的数字
  • \&:(All@V)-这是一个选择功能。它通过左接合(&:)函数All@V\,这是选择。反过来,这All@V是测试数字是否为0的一种简短方法。它的工作方式是将其输入转换为向量,0 -> [0]然后查询所有这些成员是否为真(即非0)。给出的数字位数不为0。
  • Last -这只是获得该数组的最后一个成员。

这似乎非常慢-TIO在100000测试用例上超时(1分钟)-您如何在10秒内得到1000000结果?
Toby Speight '18

@TobySpeight当我回答了这个挑战时,那个特殊要求还不存在(请检查修订历史记录)。
Conor O'Brien

啊,我应该看看历史的!您是否确实验证了问题中的所有测试用例?
Toby Speight '18

在将时间限制从问题中删除的这段时间里,似乎有很多答案-确实很不幸。
Toby Speight

@TobySpeight是的,我做到了。不幸的是,我不确定与此相关的政策。
Conor O'Brien

0

APL(Dyalog Unicode)18 15字节

{⊢/⍵/⍨0≠⍎¨⍵}⍕∘!

在线尝试!

隐式前缀功能。返回单个测试用例的正确数字,或多个测试用例的字符串。

感谢@Adám和@ErikTheOutgolfer每个3个字节。

怎么样?

{⊢/⍵/⍨0≠⍎¨⍵}⍕∘!  Main function. Argument is a number following the !.
              !  Factorial
                then
                Format (stringify)
        ⍎¨⍵}     Execute (turn to number) each digit of the argument
      0         Check if each is 0. This returns a boolean vector
                Swap arguments for the following fn/op
   ⍵/            Replicate. This takes a boolean vector as left arg and returns the truthy elements of the right arg. E.g.: 1 1 0/1 2 3  1 2.
{⊢/              Reduce. This returns the rightmost (last) element of a vector argument.

0

APL NARS,28个字节,14个字符

{↑≠v/v←⌽⍎¨⍕!⍵}

我不知道为什么,但这通过了测试:

  q←{↑≠v/v←⌽⍎¨⍕!⍵}       
  q¨1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 2 6 4 2 2 4 2 8 8 8 6 8 2 

0

AWK47 57字节

{for(p=$1;--$1;p=(p*$1)%1e4)while(!(p%10))p/=10;$0=p%10}1

在线尝试!

原始解决方案不能很好地处理“大”输入值。可能-M会迫使它正常工作,但这还需要更多的处理时间。


是啊,@TobySpeight,inf不会%很好。:(
罗伯特·本森

啊...看着我回答的问题的版本,不需要大量。
罗伯特·本森

-2

Japt,6个字节

出现了一些不同的6字节字节,但是我最喜欢这个。我相信,必须在5中做到这一点。

Êsw ìv

试试吧


说明

Ê计算输入的阶乘,s将其w反转后转换为字符串,然后转换为整数,ì将结果转换为数字数组并v返回第一个元素。


备择方案

Êì w æ
ÊìÈf Ì
Êì f o
Êsw sg
Êìf ìo
Êìf ìÌ

执行所有测试用例需要多长时间?
Toby Speight

@TobySpeight; 通过点击链接尝试进行测试非常容易。请注意,由于它们的阶乘大于JavaScript的最大整数,因此最后4个测试用例将失败。
毛茸茸的

那么,它实际上并不能解决问题吗?问题是必须成功完成1≤N≤1,000,000。其他答案表明您不需要存储阶乘就可以计算答案。
Toby Speight

我尝试了在线测试,但在我尝试的第一个测试用例(1000)上超时。
Toby Speight,

-2

Perl 5,36 + 10(-p -Mbigint)= 46字节

$"=$_;$_*=$"while$"-=1;($_)=/(.)0*$/

在线尝试!


TIO版本未能通过我尝试的前两个测试用例:1000000⇒ f(应为4)和100⇒ 7(应为4
Toby Speight,

它溢出了一个int的大小。新版本通过使用bigint起作用。性能仍然是一个蛮力计算,因此仍有一些不足之处。这意味着它在TIO上超时以获取更大的数量。
Xcali
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.