Вычислить сумму разности цифр числа

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, которое становится 04или 4, которое не может быть уменьшено далее. Суммируя все эти значения мы получаем 8675309 + 212239 + 11016 + 115 + 4 = 8898683.

Давайте определим сумму разности цифр (или DDS) как эту операцию многократного взятия разности цифр числа для формирования нового числа, а затем добавления всех полученных чисел к оригиналу.

Вот первые 20 значений в соответствующей последовательности DDS:

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.

Самый короткий код в байтах побеждает.

Кальвин Хобби
источник
лестница стоматолога?
Мартейн
12
@MartijnR Лестница стоматолога.
Увлечения Кэлвина
@ Calvin'sHobbies Лестница ортодонта?
Бета-распад
1
Лестница стоматолога @BetaDecay .
Алекс А.

Ответы:

11

Пиф, 17

s.ui.aM-VJjNTtJTQ

Попробуйте здесь или запустите Test Suite

Объяснение:

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]
FryAmTheEggman
источник
Что это за язык? Так загадочно! T_T
просит
1
@asgs Добро пожаловать в PPCG :) Он называется Pyth, вы можете найти переводчика и некоторую документацию на его странице Github . Большинство пользователей этого языка активны на этом сайте, поэтому, если у вас есть вопросы по этому поводу, не стесняйтесь задавать их в чате или в комнате, посвященной этому :)
FryAmTheEggman
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 это функция, которая вычисляет ответ.

feersum
источник
4
Что это за черная магия ?!
Бета-распад
7
@ BetaDecay Я считаю, что это называется "математика".
Lirtosiast
Я не знаю Python достаточно хорошо, чтобы сказать, но можете ли вы применить операцию остатка к обоим терминам одним ударом? То есть будет (n-n/10)%10работать так же, как n%10-n/10%10? Или, может быть, даже (9*n/10)%10?
Глен О,
@GlenO В Python %- это истинный оператор модуля, а не остаток, так что это не сработает.
feersum
15

Matlab, 101 105 байт

Большое спасибо @beaker за его предложение использовать polyvalвместо if 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, 108 104 байта

    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функция использует цифры 0, 1..., 9, A, B, ..., и есть скачок символов (ASCII) кодов от 9до A.

  • Произвольная база от 2 до 36, 124 146 байт

    Скачок от 9в Aупомянутый выше потребности специальной обработки. Максимальная база 36в соответствии с dec2baseфункцией 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
    

Вот как выглядят лестницы стоматолога для разных основ:

введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь

Луис Мендо
источник
1
Это то, что я сделал бы ... время подумать о другом ответе, лол. +1.
rayryeng - Восстановить Монику
@rayryeng :-) Спасибо
Луис Мендо
@BetaDecay Спасибо! :-) Они действительно красивые
Луис Мендо
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-мод) и формируем новое число из абсолютных разностей. Если мы получим 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();}

Ungolfed / Полная версия

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) Избавиться от statics после вытягивания их в 3), (a+"")как правило, то же самое a.toString(), но короче 4) Вам не нужен сканер, если это просто функция, просто займет много времени в качестве ввода.
Geobits
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
2
@Geobits, это было удивительно, приятель. Я новичок в Code Golf, поэтому я постараюсь улучшить свою эффективность codign. Cherrs ..
Кодер
5

Юлия, 81 60 байт

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

Попробуйте онлайн

Сохранено 21 байт благодаря feersum и Glen O!

Алекс А.
источник
1
Есть ли какая-то причина ndigits(n)>1, отличная от n>9?
февраля
Предложение: 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 Гм, нет. Благодарность!
Алекс А.
@GlenO Отлично, спасибо!
Алекс А.
5

хорошо , 37 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:

Вдохновленный решением APL @maurinus, я могу заменить «decode» ( ((#$x)#10)\x) на оценку каждого символа строкового представления числа- .:'$x! Это также позволяет мне использовать молчаливую форму всего выражения, сохраняя дополнительные символы.

Johne
источник
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:]))))

Рекурсивно добавляет текущее число и берет различия в цифрах. Много преобразования между числами и строками. Вероятно, может быть улучшено.

XNOR
источник
4

Юлия, 55 48 байтов

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

По сути, это повторяется до уровня, состоящего из одной цифры (где различие не может быть выполнено), а затем суммируется обратно при выходе из рекурсии, уровень за уровнем.

Глен О
источник
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

Кто-нибудь знает, как избежать импорта длинных функций преобразования?

Лейф Виллертс
источник
intToDigitесть toEnum.(+48)и digitToIntесть (\i->fromEnum i-48). Вы также можете перейти sк точечной версии с =<< в контексте списка: s=snd.span(==0).m abs.(zipWith(-)=<<tail). Наконец, (==0)есть (<1), потому что мы работаем с неотрицательными целыми числами.
Ними,
... а если s смысла, нет необходимости давать ему имя. Позвоните прямо:iterate(snd.span ... tail))
Ними,
... я снова исправляю ошибку в моем первом комментарии: =<<используется в контексте функции, а не в списке, извините.
Ними,
Brilliant! Кроме того, это обычная процедура здесь для использования расширений GHC? NoMonomorphismRestrictionПозвольте мне иметь без dочков тоже.
Лейф Виллертс
1
chrи ordоба Data.Char, так что вы не можете опуститьimport . Флаги компилятора также считаются байтами, поэтому NoMonomorphismRestrictionваш счет увеличивается на 25.
nimi
3

К5, 50 байт

+/{(r;x)@~r:.,/"0",{$(0;-r;r)@(~^r)+0<r:x-y}':$x}\
kirbyfan64sos
источник
3

APL (22)

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

Объяснение:

  • ⍵≤9:⍵: если ⍵ ≤ 9, вернуть ⍵ без изменений.
  • ⍎¨⍕⍵: преобразовать ⍵ в строку, затем оценить каждый символ
  • 2-/: вычтите каждые два соседних числа
  • |: принять абсолютные значения
  • 10⊥: превратить массив в число base-10
  • ⍵+∇: вызвать функцию рекурсивно с этим новым значением и добавить результат к входу
Мэринус
источник
3

Mathematica, 72 69 65 байт

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

Я открыт для предложений здесь.

LegionMammal978
источник
Tr@FixedPointList[FromDigits@*Abs@*Differences@*IntegerDigits,#]&
алефальфа
@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)))

Это не становится короче: / Я попробую больше подходов, но это самый короткий до сих пор

Downgoat
источник
Если вы просто оставляете ее как анонимную функцию, а не присваиваете ей, tона все еще действует и экономит 2 байта.
Патрик Робертс
@PatrickRoberts да, но я использую рекурсию, поэтому мне нужно назвать ее
Downgoat
Ох, пропустил это, достаточно справедливо.
Патрик Робертс
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))
edc65
источник
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 ())' позволит вам удалить преобразование int в цикле while и присвоить x. Также рассмотрите цикл по zip of g и g [1:], который должен сохранить несколько байтов.
Тодд
1

J, 70 байт

 +/([:10&#.[:(2|@:-/\])[:10&(]#:~[#~[:>.[^.])])`]@.(11&>)^:a:".(1!:1)3
протисты
источник
0

C 162 байта

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);
}
Zaibis
источник
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)}

Протестируйте это онлайн .

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

Вот график разницы между серией «Разностная сумма числа» от f (1) до f (1m). Просто потому, что я люблю дифф.

Код участка

s <- seq(1,100000)
serie <- sapply(s,f)
plot(diff(ts(serie)),xlab="",ylab="")
Mutador
источник
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)

а =

1

 b =

   16098
Abr001am
источник
Вы можете сэкономить 4 байта, пропустив необязательный ,endпараметр functionобъявления.
Андрас Дик
Пожалуйста, подумайте о пересмотре грамматики вашего поста. Я не совсем понимаю, что ты сказал.
rayryeng - Восстановить Монику
0

Пролог, 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(8675309).
8898683

Попробуйте онлайн здесь .

Emigna
источник
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;

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 байт

{[+] $_,{+.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
Брэд Гилберт b2gills
источник