计算数字的数字差总和


39

考虑采用一些非负整数(例如8675309)并计算所有相邻数字对之间的差的绝对值。

对于8675309我们得到|8-6| = 2|6-7| = 1|7-5| = 2|5-3| = 2|3-0| = 3|0-9| = 9。将这些结果串在一起会产生另一个较小的非负整数:212239。重复该过程,得到11016,然后0115,按照惯例,未写入前导零简化为115,变为044,不能再进一步减少。总结所有这些价值,我们得到8675309 + 212239 + 11016 + 115 + 4 = 8898683

让我们将数字差总和(或DDS)定义为以下操作:重复获取数字的数字差以形成新数字,然后将所有结果数字加到原始数字上。

以下是相应DDS序列中的前20个值:

N   DDS(N)
0   0
1   1
2   2
3   3
4   4
5   5
6   6
7   7
8   8
9   9
10  11
11  11
12  13
13  15
14  17
15  19
16  21
17  23
18  25
19  27

以下是前10000个值,该图非常奇怪:

DDS 10000积

尤其是当您将其绘制到1000甚至100时,它看起来相同:

DDS 1000图

DDS 100图

(我称它为牙医的楼梯 ...)

挑战

编写一个使用非负整数并打印或返回其DDS值的程序或函数。例如,如果输入为8675309,则输出应为8898683

以字节为单位的最短代码获胜。


牙医的楼梯?
Martijn

12
@MartijnR牙医的楼梯。
加尔文的爱好

@ Calvin'sHobbies正畸医生的楼梯?
Beta Decay 2015年

1
@BetaDecay 牙医的楼梯。
Alex A.

Answers:


11

佩斯,17岁

s.ui.aM-VJjNTtJTQ

在这里尝试或运行测试套件

说明:

s.u            Q   # Cumulative reduce, i.e. getting the intermediate values of each reduce
                     step and returning them as a list, then sum the list
   i ... T         # Convert the resulting list of numbers into a base 10 number
   .aM             # Get the absolute value of each element of ...
      -VJjNTtJ     # Perform vector subtraction on the lists given by
        JjNT       # assign J the number we currently have converted to its base 10 digits
            tJ     # and J[1:]. e.x. for 123 we get J = [1,2,3] then we do
                   # zip(J,J[1:]) which gives [[1,2],[2,3]] then element wise subtract
                   # to get [-1, -1]

这是什么语言?太神秘了!T_T
突袭2015年

1
@asgs欢迎使用PPCG :)名为Pyth,您可以在其Github页面上找到解释器和一些文档。该语言的大多数用户在该站点上都很活跃,因此,如果您有任何疑问,可以随时在聊天室专用
于此

17

Python 2,73

幸运的是,我设法避免了任何字符串操作。

t=lambda n:n>9and abs(n%10-n/10%10)+10*t(n/10)
g=lambda n:n and n+g(t(n))

g 是计算答案的函数。


4
这是什么黑魔法?
Beta Decay 2015年

7
@BetaDecay我相信它叫做“数学”。
lirtosiast 2015年

我不太了解Python,但您能否一击就将余数运算应用于两个术语?也就是说,其(n-n/10)%10操作方式与n%10-n/10%10?相同。或者甚至(9*n/10)%10
Glen O

@GlenO在Python中%是真正的模运算符,而不是余数,因此将无法使用。
feersum

15

Matlab,101105字节

非常感谢@beaker推荐使用polyvalif base2dec。那让我

  • 节省4个字节;
  • 大大简化了对任意基的泛化(见下文)并在那里节省了22个字节;最重要的是
  • 帮助我意识到一般情况下的代码是错误的(没有删除前导零)。代码和图形现在正确。

码:

function y=f(y)
x=+num2str(y);while numel(x)>1
x=polyval(abs(diff(x)),10);y=y+x;x=+dec2base(x,10);end

例:

>> f(8675309)
ans =
     8898683

奖励:任意基础

一个小的概括可以允许使用任意数字基数,而不必是十进制数:

  • 2至10的任意基数,108104字节

    function y=f(y,b)
    x=+dec2base(y,b);while numel(x)>1
    x=polyval(abs(diff(x)),b);y=y+x;x=+dec2base(x,b);end
    

    为什么这仅适用于基地最多的原因10是,Matlab的dec2base功能使用数字01,..., ,,9 ,...,而且也从字符(ASCII)码跳转到。AB9A

  • 从2到36的任意基数,124 146字节

    从跳转9A上面提到的需要特殊处理。最大基数36取决于Matlab的dec2base功能。

    function y=f(y,b)
    x=+dec2base(y,b);x(x>57)=x(x>57)-7;while numel(x)>1
    x=abs(diff(x));x=x(find(x,1):end);y=y+polyval(x,b);end
    

这是牙医的楼梯寻找不同基础的方式:

在此处输入图片说明 在此处输入图片说明 在此处输入图片说明 在此处输入图片说明 在此处输入图片说明 在此处输入图片说明


1
这就是我会做的...时间来考虑另一个答案。+1。
rayryeng-恢复莫妮卡2015年

@rayryeng :-)谢谢
Luis

@BetaDecay谢谢!:-)他们的确很漂亮
Luis Mendo 2015年

11

CJam,22 21字节

ri_{\s2ew::-:zsi_@+}h

请注意,该程序退出时会显示错误,默认情况下允许的

使用Java解释器,可以通过关闭STDERR来抑制错误。如果您在CJam解释器中在线尝试此代码,请忽略最后一行之前的所有输出。

感谢@ Sp3000指出原始版本中的错误。

感谢@MartinBüttner打高尔夫球1个字节。

运行示例

$ cjam digit-difference.cjam 2>&- <<< 8675309     
8898683

这个怎么运作

ri_   e# Read an integer (I) from STDIN and push a copy (A).
{     e# Do:
  \   e#   Swap I on top of A.
  s   e#   Cast I to string.
      e#   For example, 123 -> "123".
  2ew e#   Push the overlapping slices of length 2 (pair of adjacent digits).
  ::- e#   Replace each pair by its difference.
  :z  e#   Apply absolute value to each difference.
  si  e#   Cast to string, then to integer. This is the new I.
      e#   For example, [1 2 3] -> "123" -> 123.
  _   e#   Push a copy of I.
  @   e#   Rotate A on top of the copy of I.
  +   e#   Add I to A, updating A.
}h    e# While A is truthy, repeat the loop.

当由选中时,A始终是真实的h。但是,一旦是一位整数,2ew在使用了被调用的数组后,它将因错误而失败。这仅将所需的结果留在堆栈上,然后在退出之前将其打印出来。


2
发表于7分钟内:O
卡尔文的爱好

10

迷宫176 134 127 119 103 97个 88 82 79 76 72字节

感谢Sp3000节省了1个字节,并为另外2个铺平了道路。

这可能仍然可以缩短,但是,嘿,它击败了Java Matlab Python ...

?
_
)/:}+{:`};!
9       "
_ :}-"" :_10
;;{: `" "  :
  {  (_:/=%}
  0+;`"

在线尝试。

以错误终止,但是错误消息被写入STDERR(这就是为什么您在TIO中看不到它的原因)。

实现是相当简单的。我们将当前值添加到运行总计中。如果当前值大于9,我们将计算其以10为基数的数字(通过重复的div-mod),并根据绝对差值形成一个新数字。如果达到9或少于,则打印运行总计。

当前编号的数字收集在辅助堆栈中,最高有效数字在顶部。

好吧,abs(...)与新的解决方案相比,我在这里实现的幻想实现起来简直是荒谬的……当我进一步打高尔夫球时,我将添加更新的解释。


5

Java-300字节

高尔夫版

static Long t=new Scanner(System.in).nextLong();static char[]c=t.toString().toCharArray();public static void main(String[]z){while(c.length>1)s();System.out.print(t);}static void s(){String s="";for(int i=0;i<c.length-1;)s+=Math.abs(c[i]-c[++i]);Long a=new Long(s);t+=a;c=a.toString().toCharArray();}

非高尔夫版/完整版

import java.util.Scanner;

public class DigitDifference {

    static Long t = new Scanner(System.in).nextLong();
    static char[] c = t.toString().toCharArray();

    public static void main(String[] args){
        while( c.length > 1 )
            s();
        System.out.print(t);
    }

    static void s(){
        String s="";
        for(int i = 0; i < c.length-1;)
            s += Math.abs(c[i]-c[++i]);
        Long a = new Long(s);
        t += a;
        c = a.toString().toCharArray();
    }
}

@Loovjo,干杯..
编码者

1
欢迎来到PPCG!这仍然可以打很多球。我对逻辑的了解不多,但是:1)将所有这些都放到一个函数中,因为您实际上并不需要一个单独的函数(或与此相关的完整程序/类)2)static在拉出后摆脱s它们在3)(a+"")中通常与相同a.toString(),但更短4)如果它只是一个函数,则不需要Scanner,只需输入很长的时间即可。
Geobits 2015年

2
例如,在不更改大部分工作的情况下,仅除去碎屑,​​大约是164:long f(long t){long a=t;char[]c;while((c=(a+"").toCharArray()).length>1){String s="";for(int i=0;i<c.length-1;)s+=Math.abs(c[i]-c[++i]);t+=a=new Long(s);}return t;}
Geobits,2015年

2
@Geobits,那真是太好了。我是Code Golf的新手,所以我将尝试提高编码效率。Cherrs ..
The Coder

5

朱莉娅81 60字节

n->(s=n;while n>9 s+=n=int(join(abs(diff(["$n"...]))))end;s)

取消高尔夫:

function f(n::Int)
    # Initialize a sum to the input
    s = n

    while n > 9
        # Get absolute values of the pairwise differences of the
        # digits of n, join as a string, convert it to an integer,
        # and reassign n
        n = int(join(abs(diff(["$n"...]))))

        # ["$n"...] actually splits n as a string into a vector
        # of its characters, but the difference between ASCII
        # codes is the same as the difference between the numbers
        # so it works as expected

        # Add the new n to the running sum
        s += n
    end

    # Return the sum
    return s
end

在线尝试

感谢feersum和Glen O,节省了21个字节!


1
有什么ndigits(n)>1不同之处n>9吗?
feersum

建议:int(join(abs(diff(["$n"...]))))保存9个字节。n>9根据feersum的建议切换到另外9个字节。通过在while循环中一步执行两个分配(并删除多余的,现在不需要的分号),可以节省另外三个字节:n->(s=n;while n>9 s+=n=int(join(abs(diff(["$n"...]))))end;s)
Glen O

@feersum嗯,不。谢谢!
Alex A.

@GlenO太好了,谢谢!
Alex A.

5

OK37 32 24 23字节

+/(10/{%x*x}1_-':.:'$)\

实际上:

  +/(10/{%x*x}1_-':.:'$)\8675309
8898683

  (+/(10/{%x*x}1_-':.:'$)\)'!20
0 1 2 3 4 5 6 7 8 9 11 11 13 15 17 19 21 23 25 27

K5具有一些非常适合此功能的功能-“编码”和“解码”可以执行基本转换,每对(':)将列表中的顺序元素配对,定点扫描(\)可以产生迭代序列,直到停止为止变化。不过,缺少基本类型abs()会导致一些难看的形式为的体积{(x;-x)x<0}'

编辑:

取而代之的是{(x;-x)x<0}',我可以(有点浪费)获取序列平方的平方根({%x*x},节省5个字节。

编辑2:

受@maurinus的APL解决方案的启发,我可以((#$x)#10)\x通过评估数字的字符串表示形式的每个字符来代替“解码”().:'$x!这也使我可以使用整个表达式的默认形式,从而节省了其他字符。


4

Python 2,87字节

f=lambda n:n and n+f(int('0'+''.join(`abs(int(a)-int(b))`for a,b in zip(`n`,`n`[1:]))))

递归地添加当前数字并取数字差。在数字和字符串之间进行大量转换。可能可以改善。


4

朱莉娅,55 48字节

h=n->(n>9&&h(int(join(abs(diff(["$n"...]))))))+n

取消高尔夫:

function h(n)
  if n>9
    # If multiple digits, find the digit difference...
    digitdiff=int(join(abs(diff(["$n"...]))))
    # ... recurse the function...
    downsum=h(digitdiff)
    # ... and return the sum so far (working up from the bottom)
    return downsum+n
  else
    # If single digit, no further recursion, return the current number
    return n
  end
end

本质上,这递归递归到个位数的级别(在这里不能执行数字差),然后在退出递归时逐级求和。


3

Haskell,140字节

d 做这份工作。

import Data.Char
d n=sum.m(read.m intToDigit).fst.span(/=[]).iterate s.m digitToInt.show$n
s l@(h:t)=snd$span(==0)$m abs$zipWith(-)l t
m=map

有谁知道如何避免导入长转换函数?


intToDigittoEnum.(+48)并且digitToInt(\i->fromEnum i-48)。您还可以在列表上下文中s使用转换为无点版本 。最后是,因为我们正在使用非负整数。=<<s=snd.span(==0).m abs.(zipWith(-)=<<tail)(==0)(<1)
nimi

...哦,如果s它没有意义,则无需为其命名。直接致电:iterate(snd.span ... tail))
nimi

...是我再次纠正我的第一个注释中的错误:=<<抱歉,在函数上下文中使用,而不是在列表上下文中使用。
nimi 2015年

辉煌!另外,在这里使用GHC扩展名是通用程序吗?NoMonomorphismRestriction也让我d毫无意义。
Leif Willerts

1
chr而且ord都在Data.Char,所以你不能省略import。编译器标记也计为字节,因此NoMonomorphismRestriction
会将


3

APL(22)

{⍵≤9:⍵⋄⍵+∇10⊥|2-/⍎¨⍕⍵}

说明:

  • ⍵≤9:⍵:如果⍵≤9,则返回⍵不变。
  • ⍎¨⍕⍵:将convert转换为字符串,然后评估每个字符
  • 2-/:每两个相邻的数字相减
  • |:取绝对值
  • 10⊥:将数组转换为以10为底的数字
  • ⍵+∇:使用此新值递归调用函数,并将结果添加到输入中

3

Mathematica,72 69 65字节

Tr@FixedPointList[FromDigits@*Abs@*Differences@*IntegerDigits,#]&

我愿意在这里提出建议。


Tr@FixedPointList[FromDigits@*Abs@*Differences@*IntegerDigits,#]&
alephalpha

@alephalpha有趣的概念,创造了额外的零...
LegionMammal978

2

JavaScript ES6,73个字节

t=n=>(b=10,M=Math).ceil(n&&n+t((j=n=>n>9&&M.abs(n%b-n/b%b)+b*j(n/b))(n)))

这不会越来越短:/我将尝试更多方法,但这是迄今为止最短的方法


如果您只是将其保留为匿名函数而不是将其分配给它,t则它仍然有效并为您节省2个字节。
Patrick Roberts

@PatrickRoberts是的,但是我正在使用递归,所以我需要命名它
Downgoat 2015年

哦,错过了,很公平。
Patrick Roberts 2015年

2

JavaScript(ES6),69

测试在符合EcmaScript 6的浏览器中运行以下代码段(但不支持Chrome,因为它仍然不支持散布运算符...)。MS Edge可能吗?

f=n=>n&&(n+=r='',[...n].map(d=>(r+=d>p?d-p:p-d,p=d),p=n[0]),+n+f(+r))

function test()
{
  var i=+I.value
  O.innerHTML = i+' -> '+f(i) + '\n' + O.innerHTML 
}
<input id=I value=8675309><button onclick=test()>-></button>
<pre id=O></pre>

或者,使用现在针对EcmaScript 2016(ES7)的数组理解(67字节):

f=n=>n&&(n+=r='',p=n[0],[for(d of n)(r+=d>p?d-p:p-d,p=d)],+n+f(+r))

2

Python 3,125个字节

我以前喜欢的正则表达式的急促,直到我试图使用它的这一挑战...... re.findall('\d\d',s,overlapped=True)不是上;)

s=input()
p=int
x=p(s)
while p(s)>9:g=str(s);s=p(''.join(str(abs(p(g[i])-p(g[i+1])))for i in range(len(g)-1)));x+=s 
print(x)

干杯@Todd :)


1
您可以在整数而不是列表上执行就地加法,这将消除对方括号和最后的总和的需要。's = p(input())'将允许您删除while循环上的int转换并分配给x。还可以考虑循环遍历g和g [1:]的zip文件,这应该节省一些字节。
2015年

1

J,70个字节

 +/([:10&#.[:(2|@:-/\])[:10&(]#:~[#~[:>.[^.])])`]@.(11&>)^:a:".(1!:1)3

0

C 162字节

打高尔夫球:

main(int argc,char **argv){char *c=argv[1];int u=atoi(c),d;do{while(c[1]!=0){*c=abs(*c-*(c+1))+48;c++;}*c=0;c=argv[1];d=atoi(c);u+=d;}while(d>9);printf("%d",u);}

松散:

main(int argc, char **argv)
{
    char *c=argv[1];
    int u=atoi(c),d;

    do
    {
        while(c[1]!=0)
        {
            *c=abs(*c-*(c+1))+48;
            c++;
        }

        *c=0;
        c=argv[1];
        d=atoi(c);
        u+=d;
    }
    while(d>9);

    printf("%d\n",u);
}

0

R,134字节

f=function(x){z=x;while(z>9){n=seq(nchar(z));z=abs(diff(strtoi(substring(z,n,n))));z=sum(z*10**(rev(seq(length(z)))-1));x=x+z};cat(k)}

在线测试。

不打高尔夫球

f=function(x){
  z=x;
  while(z>9){
    n=seq(nchar(z));
    z=abs(diff(strtoi(substring(z,n,n))));
    z=sum(z*10**(rev(seq(length(z)))-1));
    x=x+z
  };
  cat(x)
}

这是从f(1)到f(1m)的“数字的数字差异和”系列的差异图。只是因为我喜欢差异。

情节代码

s <- seq(1,100000)
serie <- sapply(s,f)
plot(diff(ts(serie)),xlab="",ylab="")

0

的MATLAB (141)(137)

编辑:少了4个字节,这要感谢@Andras

function[s j]=n(T,b,c),if(T/b>9),u=fix(T/10);[x e]=n(T,b*10,0);y=n(u,b,0);[w z]=n(u,b,c);s=abs(x-y);j=s+e+10*c*z;else,s=mod(T,10);j=s;end
  • 这并没有超过@LuisMendo的答案,但是我至少可以减少执行时间,通过这种方式,我将试图以多样化的方式来解决该问题。
  • 我可以减少更多的空间,但是随着时间的流逝,我浪费了更多的字节,因此原理如下:

该程序将内联数字之前的同一行数字相加,这确实意味着它仅使用整数除法“ n / 10” log_10(n)倍,复杂度为O(N)。

如果 n= a b c d

a          b           c           d
   |a-b|       |b-c|       |c-d|
    ||a-b|-|b-c|| ||b-c|-|c-d||
   ....

我的程序计算:

a+|a-b| + | |a-b|-|b-c| |  +  |  | |a-b|-|b-c| | - | |b-c|-|c-d| |  |
+10*(
b+|b-c| + | |b-c|-|c-d| |
+10*(
c+|c-d|
+10*(
d
)
)
)

用法:

  [a b]=n(13652,1,1)

a =

1个

 b =

   16098

您可以通过省略声明的可选,end部分来保留4个字节function
Andras Deak

请考虑修改帖子的语法。我不太明白你在说什么。
rayryeng-恢复莫妮卡2015年

0

Prolog,143字节

码:

q(X,N):-X<9,N=0;A is abs(X mod 10-X//10 mod 10),Y is X//10,q(Y,M),N is A+M*10.
r(X,N):-X<9,N=X;q(X,Y),r(Y,M),N is X+M.
p(X):-r(X,N),write(N).

解释:

q(X,N):-X<9,N=0;                                                         % If only one digit, the difference is 0
        A is abs(X mod 10-X//10 mod 10),Y is X//10,q(Y,M),N is A+M*10.   % Else, the difference is the difference between the last 2 digits + the recursive difference of the number without the last digit
r(X,N):-X<9,N=X;                                                         % If we only have 1 digit the final answer is that digit
        q(X,Y),r(Y,M),N is X+M.                                          % Else, the final answer is the current number + the recursive difference of that number
p(X):-r(X,N),write(N).         

q进行将数字转换为数字差的计算。
r递归调用q并对结果求和以求出数字差和。
p是入口点。取一个数字,呼叫r并打印答案。

例:

>p(8675309).
8898683

在这里在线尝试。


0

PHP-198字节

<?$x=$t=$_GET['V'];function z($x){global$t;for($i=0;$i<strlen($x)-1;$i++){$z=str_split($x);$r.=str_replace('-','',$z[$i]-$z[$i+1]);}$r=ltrim($r,'0');$t+=$r;return strlen($r)>1?z($r):0;}z($x);echo$t;

不打高尔夫球

<?
$x=$t=$_GET['V']; // Gets the value from input
function z($x){
    global$t;
    for($i=0;$i<strlen($x)-1;$i++){
        $z=str_split($x); //Turns the string into an array
        $r.=str_replace('-','',$z[$i]-$z[$i+1]); // Sums the two values and removes the minus signal
    }
    $r=ltrim($r,'0'); // Remove trailing zeroes
    $t+=$r; // Adds to global var
    return strlen($r)>1?z($r):0; // Checks the size of the string. If >1, calls the function again
}

z($x);
echo$t;

0

Perl 6、56个字节

{[+] $_,{+.comb.rotor(2=>-1)».map((*-*).abs).join}…0} # 56 bytes

用法:

my &code = {...} # insert code from above

(180..190).map: &code;
# (259 258 259 260 261 262 263 264 265 266 280)

say code 8675309; # 8898683
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.