Calcular a soma da diferença de dígitos de um número


39

Considere pegar um número inteiro não negativo como 8675309 e calcular os valores absolutos das diferenças entre todos os pares de dígitos vizinhos.

Para 8675309chegarmos |8-6| = 2, |6-7| = 1, |7-5| = 2, |5-3| = 2, |3-0| = 3, |0-9| = 9. Amarrando estes resultados em conjunto produz uma outra menor número inteiro, não-negativo: 212239. Repetir o processo fornece 11016, então 0115, que pela convenção de que os zeros à esquerda não são escritos simplifica como 115, o que se torna 04ou 4que não pode mais ser reduzido. Resumindo todos esses valores, obtemos 8675309 + 212239 + 11016 + 115 + 4 = 8898683.

Vamos definir a soma da diferença de dígitos (ou DDS) como esta operação de tirar repetidamente as diferenças de dígitos de um número para formar um novo número e adicionar todos os números resultantes ao original.

Aqui estão os 20 primeiros valores na sequência DDS correspondente:

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

Aqui estão os primeiros 10000 valores , cujo gráfico é bastante curioso:

DDS 10000 plot

Especialmente porque parece o mesmo quando você planeja 1000 ou mesmo 100:

Gráfico DDS 1000

Gráfico DDS 100

(Eu chamaria de escada do dentista ...)

Desafio

Escreva um programa ou função que receba um número inteiro não negativo e imprima ou retorne seu valor DDS. Por exemplo, se a entrada foi 8675309, a saída deve ser 8898683.

O código mais curto em bytes vence.


escada do dentista?
Martijn

12
@MartijnR Escada do dentista.
Calvin's Hobbies

@ Escada do Calvin'sHobbies Ortodontista?
Beta Decay

1
@BetaDecay Escada do dentista .
Alex A.

Respostas:


11

Pyth, 17

s.ui.aM-VJjNTtJTQ

Experimente aqui ou execute o Test Suite

Explicação:

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]

Que língua é essa? Tão enigmático! T_T
asgs

1
@asgs Bem-vindo ao PPCG :) Chama-se Pyth, você pode encontrar um intérprete e alguma documentação na página do Github . A maioria dos usuários desta linguagem são ativos neste site, por isso, se você tiver dúvidas sobre isso não hesite em perguntar no bate-papo ou na sala dedicada a ele :)
FryAmTheEggman

17

Python 2, 73

Felizmente, consegui evitar qualquer operação de string.

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 é a função que calcula a resposta.


4
O que é essa magia negra ?!
Beta Decay

7
@BetaDecay Eu acredito que é chamado de "matemática".
lirtosiast 21/09/2015

Não conheço Python o suficiente para saber, mas você pode aplicar a operação restante aos dois termos em um único hit? Ou seja, (n-n/10)%10operaria da mesma forma que n%10-n/10%10? Ou talvez até (9*n/10)%10?
Glen O

@GlenO No Python, %é um verdadeiro operador de módulo, não um restante, para que não funcione.
feersum

15

Matlab, 101 105 bytes

Muito obrigado a @beaker por sua sugestão de usar o polyvalif base2dec. Isso me permitiu

  • economize 4 bytes;
  • simplifique bastante a generalização para base arbitrária (veja abaixo) e salve 22 bytes lá; e acima de tudo,
  • me ajudou a perceber que o código do caso geral estava errado (os zeros à esquerda não estavam sendo removidos). O código e os gráficos estão corretos agora.

Código:

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

Exemplo:

>> f(8675309)
ans =
     8898683

Bônus: base arbitrária

Uma pequena generalização permite que se use uma base numérica arbitrária, não necessariamente decimal:

  • Base arbitrária de 2 a 10, 108 104 bytes

    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
    

    A razão pela qual isto funciona apenas para a base até 10é que MATLAB dec2baseusa a função dígitos 0, 1, ..., 9, A, B, ..., e há um salto em códigos de caracteres (ASCII) a partir 9de A.

  • Base arbitrária de 2 a 36, 124 146 bytes

    O salto 9da Areferida necessidades acima de tratamento especial. A base máxima é de 36acordo com a dec2basefunção do Matlab .

    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
    

É assim que as escadas do dentista procuram bases diferentes:

insira a descrição da imagem aqui insira a descrição da imagem aqui insira a descrição da imagem aqui insira a descrição da imagem aqui insira a descrição da imagem aqui insira a descrição da imagem aqui


1
Isto é o que eu teria feito ... tempo para pensar em outra resposta lol. +1.
rayryeng - Restabelece Monica

@rayryeng :-) Obrigado
Luis Mendo

@BetaDecay Thanks! :-) Eles são bem verdadeiros
Luis Mendo

11

CJam, 22 21 bytes

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

Observe que este programa sai com um erro, o que é permitido por padrão .

Com o interpretador Java, os erros podem ser suprimidos ao fechar STDERR. Se você tentar esse código online no interpretador CJam , ignore toda a saída antes da última linha.

Agradecemos ao @ Sp3000 por apontar um erro na revisão original.

Agradecemos a @ MartinBüttner por jogar 1 byte.

Exemplo de execução

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

Como funciona

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 sempre será verdadeira quando marcada por h. No entanto, quando eu for um número inteiro de um dígito, 2ewfalhará com um erro depois de consumir a matriz na qual ela foi chamada. Isso deixa apenas o resultado desejado na pilha, que é impressa antes de sair.


2
Postado em 7 minutos plana: O
Calvin's Hobbies

10

Labirinto , 176 134 127 119 103 97 88 82 79 76 72 bytes

Agradecemos ao Sp3000 por economizar 1 byte e abrir caminho para mais 2.

Provavelmente isso ainda pode ser reduzido, mas, ei, ele vence o Java Matlab Python ...

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

Experimente online.

Isso termina com um erro, mas a mensagem de erro é gravada em STDERR (e é por isso que você não a vê no TIO).

A implementação é bastante direta. Adicionamos o valor atual a um total em execução. Se o valor atual for maior que 9, calculamos seus dígitos da base 10 (via div-mod repetido) e formamos um novo número a partir das diferenças absolutas. Se chegarmos a 9ou menos, imprimimos o total em execução.

Os dígitos do número atual são coletados na pilha auxiliar com o dígito mais significativo no topo.

Bem, a implementação sofisticada de que abs(...)eu tinha aqui se mostrou ridiculamente complicada em comparação com a nova solução ... Vou adicionar uma explicação atualizada quando terminar de jogar ainda mais.


5

Java - 300 bytes

Versão Golfed

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();}

Ungolfed / Versão completa

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, Cheers ..
The Coder

1
Bem-vindo ao PPCG! Isso ainda pode ser muito praticado. Eu não olhei muito para a lógica, mas: 1) Coloque tudo isso em uma única função, pois você realmente não precisa de uma separada (ou de um programa / aula completo) 2) Livre-se dos statics depois de puxá-los eles em 3) (a+"")geralmente são iguais a.toString(), mas mais curtos 4) Você não precisa de um scanner, se for apenas uma função, basta demorar um pouco para entrar.
Geobits 22/09/2015

2
Por exemplo, sem alterar muito do trabalho, e apenas removendo cruft, é em torno de 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

2
@ Geobits, que amigo incrível. Eu sou novo no Code Golf, então tentarei melhorar minha eficiência de codinome. Cherrs ..
O codificador

5

Julia, 81 60 bytes

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

Ungolfed:

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

Experimente online

Economizou 21 bytes graças a feersum e Glen O!


1
Existe algum motivo ndigits(n)>1diferente n>9?
feersum

Sugestão: int(join(abs(diff(["$n"...]))))salva 9 bytes. Alterne para n>9conforme sugerido por feersum para outros 9 bytes salvos. Guardar mais três bytes por realizar ambos os trabalhos no while em um passo (e removendo o extra, ponto e vírgula agora desnecessárias):n->(s=n;while n>9 s+=n=int(join(abs(diff(["$n"...]))))end;s)
Glen O

@feersum Hum, não. Obrigado!
Alex A.

@GlenO Awesome, obrigado!
Alex A.

5

OK , 37 32 24 23 bytes

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

Em ação:

  +/(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

O K5 possui alguns recursos que são bem adequados para isso - "codificar" e "decodificar" podem executar a conversão base, cada par ( ':) emparelha elementos seqüenciais em uma lista e a varredura de ponto fixo ( \) pode produzir a sequência iterada até que pare mudando. A falta de um primitivo abs()leva a um volume desagradável na forma de {(x;-x)x<0}', no entanto.

Editar:

Em vez de {(x;-x)x<0}', posso (de maneira um tanto inútil) pegar a raiz quadrada do quadrado da sequência ( {%x*x}economizando 5 bytes).

Edição 2:

Inspirado na solução APL do @maurinus, posso substituir o "decode" ( ((#$x)#10)\x) pela avaliação de cada caractere da representação de string do número- .:'$x! Isso também permite que eu use uma forma tácita de toda a expressão, salvando caracteres adicionais.


4

Python 2, 87 bytes

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

Adiciona recursivamente o número atual e leva as diferenças de dígitos. Muita conversão entre números e seqüências de caracteres. Provavelmente pode ser melhorado.


4

Julia, 55 48 bytes

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

Ungolfed:

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

Essencialmente, isso volta ao nível de um dígito (onde nenhuma diferença de dígito pode ser executada) e, em seguida, soma novamente quando sai da recursão, nível por nível.


3

Haskell, 140 bytes

d faz o trabalho.

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

Alguém sabe como evitar a importação das longas funções de conversão?


intToDigité toEnum.(+48)e digitToInté (\i->fromEnum i-48). Você também pode ligar spara uma versão pointfree com =<<no contexto de lista: s=snd.span(==0).m abs.(zipWith(-)=<<tail). Finalmente, (==0)é (<1)porque estamos trabalhando com números inteiros não negativos.
nimi

... ah, e se sfor sem sentido, não há necessidade de dar um nome a ele. Chame-o diretamente:iterate(snd.span ... tail))
nimi

... sou eu novamente para corrigir um erro no meu primeiro comentário: =<<é usado no contexto da função, não no contexto da lista, desculpe.
nimi

Brilhante! Além disso, é procedimento comum aqui usar extensões do GHC? NoMonomorphismRestrictionvai me deixar sem dpontos também.
Leif Willerts

1
chre ordestão ambos dentro Data.Char, então você não pode omitir o import. Bandeiras do compilador são contados como bytes, também, então NoMonomorphismRestrictionaumenta sua pontuação 25.
nimi


3

APL (22)

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

Explicação:

  • ⍵≤9:⍵: se ≤ 9, retorne ⍵ inalterado.
  • ⍎¨⍕⍵: converte ⍵ em uma sequência e avalie cada caractere
  • 2-/: subtraia a cada dois números adjacentes
  • |: pegue os valores absolutos
  • 10⊥: transforme a matriz em um número de base 10
  • ⍵+∇: chame a função recursivamente com esse novo valor e adicione o resultado à entrada

3

Mathematica, 72 69 65 bytes

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

Estou aberto a sugestões aqui.


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

@alephalpha conceito interessante, criando zeros extras ...
LegionMammal978

2

JavaScript ES6, 73 bytes

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)))

Isso não está ficando mais curto: / Vou tentar mais abordagens, mas essa é a mais curta até agora


Se você simplesmente deixá-lo como uma função anônima, em vez de atribuí- tlo, ainda é válido e economiza 2 bytes.
Patrick Roberts

@PatrickRoberts sim, mas eu estou usando recursão então eu preciso nomeá-lo
Downgoat

Oh, senti falta disso, é justo.
Patrick Roberts

2

JavaScript (ES6), 69

Teste a execução do snippet abaixo em um navegador compatível com EcmaScript 6 (mas não o Chrome, pois ainda não suporta o operador de propagação ...), talvez o 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>

Alternativa, usando a compreensão da matriz agora direcionada ao EcmaScript 2016 (ES7), 67 bytes:

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 bytes

Eu gostava da falta de regex até tentar usá-lo para esse desafio ... nãore.findall('\d\d',s,overlapped=True) está ativado ;)

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)

Cheers @Todd :)


1
Você pode executar a adição local em um número inteiro, em vez de em uma lista que removerá a necessidade de colchetes e a soma final. 's = p (input ())' permitirá remover a conversão int no loop while e atribuir a x. Considere também fazer um loop pelo zip de g [1:], o que deve economizar alguns bytes.
Todd

1

J, 70 bytes

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

0

C 162 bytes

golfed:

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);}

ungolfed:

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 bytes

Código

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)}

Teste online .

Ungolfed

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)
}

Aqui está o gráfico da diferença da série "Soma de diferença de dígitos de um número" de f (1) para f (1m). Só porque eu amo diferenciar.

Código de plotagem

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

0

MATLAB (141)(137)

EDIT: menos 4 bytes, graças a @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
  • Este fato superou a resposta de @LuisMendo, mas pelo menos eu poderia reduzir o tempo de execução, o que, apenas tentaria diversificar as formas de resolver esse problema.
  • Eu poderia reduzi-lo mais, mas como passo menos tempo, perco mais bytes, então aqui está o princípio:

O programa está somando dígitos da mesma linha antes dos dígitos incorporados, significa que ele usou a divisão inteira "n / 10" log_10 (n) apenas vezes, a complexidade é O (N).

E se n= a b c d

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

Meu programa calcula:

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
)
)
)

Uso:

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

a =

1

 b =

   16098

Você pode poupar 4 bytes, omitindo o opcional ,endda functiondeclaração.
Andras Deak

Por favor, considere revisar a gramática da sua postagem. Não consigo entender direito o que você disse.
rayryeng - Restabelece Monica

0

Prolog, 143 bytes

Código:

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).

Explicado:

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 faz os cálculos que convertem um número em sua diferença de dígitos.
r chama recursivamente q e resume os resultados para encontrar a soma da diferença de dígitos.
p é o ponto de entrada. Pega um número, liga r e imprime a resposta.

Exemplo:

>p(8675309).
8898683

Experimente online aqui .


0

PHP - 198 bytes

<?$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;

Ungolfed

<?
$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 bytes

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

uso:

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.