Обчислити суму різниці цифр числа


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 значень , графік яких досить цікавий:

Діаграма 10000 DDS

Тим більше, що це виглядає так само, коли ви плануєте його на 1000 або навіть 100:

Сюжет DDS 1000

Сюжет DDS 100

(Я б назвав це сходами стоматолога ...)

Виклик

Напишіть програму або функцію, яка приймає невід'ємне ціле число і друкує або повертає її значення DDS. Наприклад, якщо вхід був 8675309, вихід повинен бути 8898683.

Виграє найкоротший код у байтах.


сходи стоматолога?
Martijn

12
@MartijnR Сходи стоматолога.
Захоплення Кальвіна

@ Сходи Calvin'sHobbies Ортодонт?
Бета-розпад

1
@BetaDecay Сходи стоматолога .
Алекс А.

Відповіді:


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
асгс

1
@asgs Ласкаво просимо до PPCG :) Це називається Pyth, ви можете знайти перекладача та деяку документацію на його сторінці Github . Більшість користувачів цієї мови активні на цьому веб-сайті, тому, якщо у вас є питання про неї, не соромтесь задавати питання в чаті або кімнаті, присвяченій їй :)
FryAmTheEggman

17

Пітон 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
Що це за чорна магія ?!
Бета-розпад

7
@BetaDecay Я вважаю, що це називається "математика".
lirtosiast

Я не знаю Python досить добре, щоб сказати, але чи можете ви застосувати решту операцій до обох термінів одним ударом? Тобто, (n-n/10)%10діяв би так само, як n%10-n/10%10? А може, навіть (9*n/10)%10?
Глен О

@GlenO У Python %- це справжній оператор модуля, а не залишок, тому це не працює.
feersum

15

Матлаб, 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функції Матлаба .

    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 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, Cheers ..
Кодер

1
Ласкаво просимо до PPCG! Це ще можна багато в гольф. Я не дуже придивився до логіки, але: 1) перетягніть все це в одну функцію, оскільки вам не потрібен окремий (або повна програма / клас для цього) 2) Позбавтеся від statics після витягування їх у 3) (a+"")загалом те саме a.toString(), але коротше 4) Сканер вам не потрібен, якщо це лише функція, просто введіть довгий вхід.
Геобіт

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, тому спробую підвищити ефективність кодування. Cherrs ..
Кодер

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

Спробуйте в Інтернеті

Збережено 21 байт завдяки feersum та Glen O!


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 Гм, ні. Спасибі!
Олексій А.

@GlenO Чудово, дякую!
Алекс А.

5

oK , 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, я можу замінити "декодування" ( ((#$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

Хтось знає, як уникнути імпорту довгих функцій перетворення?


intToDigitє toEnum.(+48)і digitToIntє (\i->fromEnum i-48). Ви також можете звернутися sдо версії pointfree з =<<в контексті списку: s=snd.span(==0).m abs.(zipWith(-)=<<tail). Нарешті, (==0)є (<1), тому що ми працюємо з невід'ємними цілими числами.
німі

... о, і якщо sце точково, не потрібно давати йому ім'я. Телефонуйте безпосередньо:iterate(snd.span ... tail))
nimi

... це я знову, щоб виправити помилку в своєму першому коментарі: =<<використовується в контексті функції, а не в контексті списку, вибачте.
німі

Блискуче! Також чи поширена тут процедура використання розширень GHC? NoMonomorphismRestrictionдозволить мені і dточково.
Лейф Віллертс

1
chrі ordвони обоє Data.Char, тому ви не можете опустити це import. Прапорці компілятора також зараховуються до байтів, тому NoMonomorphismRestrictionзбільшує свою оцінку на 25.
nimi


3

APL (22)

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

Пояснення:

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

3

Математика, 72 69 65 байт

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

Я відкритий для пропозицій тут.


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

Це не стає коротшим: / Я спробую більше підходів, але це найкоротший досі


Якщо ви просто залишите її як анонімну функцію замість того, щоб призначати її, 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))

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 і призначити х. Також розглянемо прокручування через блискавку g та g [1:], яка повинна зберегти деякі байти.
Тодд


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)

EDIT: на 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

Ви можете заощадити 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 - точка входу. Бере номер, дзвонить 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.