Зворотна колумбійська функція


28

Давайте визначимо послідовність: Послідовність підсумовування n знаків (n-DSS) - це послідовність, яка починається з n . Якщо останнє число було k , то наступне число - k + цифра-сума (k) . Ось перші кілька n-DSS:

1-DSS: 1, 2, 4, 8, 16, 23, 28, 38, 49, 62, 70...
2-DSS: 2, 4, 8, 16, 23, 28, 38, 49, 62, 70, 77...
3-DSS: 3, 6, 12, 15, 21, 24, 30, 33, 39, 51, 57...
4-DSS: 4, 8, 16, 23, 28, 38, 49, 62, 70, 77, 91...
5-DSS: 5, 10, 11, 13, 17, 25, 32, 37, 47, 58, 71...
6-DSS: 6, 12, 15, 21, 24, 30, 33, 39, 51, 57, 69...
7-DSS: 7, 14, 19, 29, 40, 44, 52, 59, 73, 83, 94...
8-DSS: 8, 16, 23, 28, 38, 49, 62, 70, 77, 91, 101...
9-DSS: 9, 18, 27, 36, 45, 54, 63, 72, 81, 90, 99...

Для 1 це A004207 , хоча перші кілька цифр відрізняються через дещо інше визначення. Для 3 це A016052 ; для 9, A016096 .

Сьогоднішнє завдання полягає в тому, щоб знайти послідовність найменших n цифр, в якій відображається задане число. Це називається "зворотна колумбійська функція", і це A036233 . Перші двадцять термінів, починаючи з 1:

1, 1, 3, 1, 5, 3, 7, 1, 9, 5, 5, 3, 5, 7, 3, 1, 5, 9, 7, 20

Деякі інші хороші тестові випадки:

117: 9
1008: 918

Вам потрібно обробляти лише цілі числа, що перевищують 0, і ви можете приймати введення та вихід у будь-якому стандартному форматі. Як завжди, це , тому найкоротша відповідь на кожній мові виграє.


Відповіді:


12

Haskell , 104 64 63 байт

(-26 завдяки H.PWiz, додатково -14 завдяки сріотчілізму О'Заїку, додаткові -1 завдяки коулу)

Це функція.

f x=[y|y<-[1..],x==until(>=x)(foldr((+).read.pure)<*>show)y]!!0

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


Пояснення:

(foldr((+).read.pure)<*>show)

Послідовність складених функцій, яка повертає y + цифрову суму y. Спочатку перетворюється на рядок, потім виконується гімнастика монади, щоб отримати суму символів та початкове число (завдяки Коулу).

<*>Оператор в цьому контексті має тип і визначення

(<*>) :: (a -> b -> c) -> (a -> b) -> c
f <*> g = \x -> f x (g x)

тому ми можемо записати вище як

\x -> foldr ((+) . read . pure) x (show x)

Це read . pureперетворює a Charв число, тому (+) . read . pure :: Char -> Int -> Intдодає цифру до накопиченого значення. Це значення ініціалізується на задане число в складці.

until (>=x) {- digital sum function -} y

untilнеодноразово застосовує функцію до її результату (в даному випадку цифрову суму y + y), поки вона не відповідає вимозі, визначеній функцією в першому аргументі. Це дає найменший y-DSS елемент, більший або рівний x.

[y | y<-[1..]; x == {- smallest y-DSS element >= x -} ]

Нескінченний лінивий список y такий, що найменший елемент Y-DSS> = x насправді x. Використовує нотацію розуміння списку Хаскелла (про яку я теж зовсім забув, дякую всім).

f x = {- aforementioned list -} !! 0

Перший елемент цього списку, який є найменшим y, який відповідає вимозі виклику.


1
Ось як я пограв у нього в гольф.
H.PWiz

1
@ H.PWiz Це повинно бути те саме ні? Я б так подумав, але ваше використання fmapв першу чергу мене трохи бентежить.
Пшеничний майстер

1
Гаразд, це зайняло багато фенанглінгу, але я зловживав монадою читача, щоб поголити один байт. Код Woohoo pointfree! TIO
cole

@ SriotchilismO'Zaic Cool. Я просто гольфував код механічно, не замислюючись над цим
H.PWiz

1
Не знаєте, як редагувати запит на мобільному, тому я щойно відредагував пояснення свого коду - не соромтеся змінювати або скачувати назад.
cole


4

Perl 6 , 44 байти

->\a{+(1...{a∈($_,{$_+.comb.sum}...*>a)})}

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

Наївне рішення, яке перевіряє кожну послідовність, поки не знайде те, що містить вхід

Пояснення:

->\a{                                    }  # Anonymous code block taking input as a
     +(1...{                           })   # Find the first number
            a∈(                       )     # Where the input is an element of
                                ...         # The sequence
               $_,                          # Starting with the current number
                  {            }   # Where each element is
                   $_+             # Is the previous element plus
                      .comb.sum    # The digit sum
                                   *>a      # Until the element is larger than the input



3

MATL , 18 байт

`@G:"ttFYAs+]vG-}@

Спробуйте в Інтернеті! Або перевірте перші 20 значень .

Пояснення

Для введення iце продовжує збільшуватися nдо тих пір, поки не будуть включені перші iчлени nпослідовності i. Достатньо перевірити iтерміни для кожної послідовності, оскільки послідовність збільшується.

`         % Do...while
  @       %   Push iteration index, n. This is the firsrt term of the n-th sequence
  G:      %   Push [1 2 ... i], where i is the input
  "       %   For each (i.e., do the following i times)
    tt    %     Duplicate twice
    FYA   %     Convert to digits
    s     %     Sum
    +     %     Add to previous term. This produces a new term of the n-th sequence
  ]       %   End
  v       %   Concatenate all terms into a column vector
  G-      %   Subtract i, element-wise. This is the do...while loop condition (*).
}         % Finally (this is executed right before exiting the loop)
  @       %   Push current n. This is the output, to be displayed
          % End (implicit). A new iteration will start if all terms of (*) are nonzero
          % Display (implicit)

3

Четвертий (gforth) , 106 байт

: f
>r 0 begin 1+ dup begin dup i < while dup begin 10 /mod >r + r> ?dup 0= until repeat i = until rdrop
;

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

Пояснення коду

: f                \ start a new word definition
  >r               \ store the input on the return stack for easy access
  0                \ set up a counter
  begin            \ start an indefinite loop
    1+ dup         \ add 1 to the counter and duplicate
    begin          \ start a 2nd indefinite loop
      dup i <      \ check if current value is less than the input value
    while          \ if it is, continue with the inner loop
      dup          \ duplicate the current value
      begin        \ innermost loop, used to get the digit-wise sum of a number
        10 /mod    \ get quotient and remainder of dividing by 10
        >r + r>    \ add remainder to current list value
        ?dup 0=    \ check if quotient is 0
      until        \ end the innermost loop if it is
    repeat         \ go back to the beginning of the 2nd loop
    i =            \ check if the "last" value of the current list = the input value
  until            \ if it does, we're done
  rdrop            \ remove the input value from the return stack
;                  \ end the word definition    

3

Pyth , 13 байт

fqQ.W<HQ+ssM`

Спробуйте тут або ознайомтеся з тестовим набором .


Як це працює

fqQ.W<HQ+ssM`     Full program. Takes input Q from STDIN, writes to STDOUT.
f{...}            Loop over 1,2,3,... and find the first number to yield truthy results when
                     applying the function {...} (whose variable is T = the current integer).
 qQ.W<HQ+ssM`     The function {...}, which will be analysed separately.
   .W             Functional while. While condition A is true, do B.
     <HQ          Cond. A (var: H - starts at T): Checks if H is less than Q.
        +ssM`     Func. B (var: G - G & H are the same): If A, G & H become G+digit sum(G)
                  The last value of this functional while will be the least possible number N
                  in the T-DSS that is greater than or equal to Q.
                  If N = Q, then Q ∈ T-DSS. Else (if N > Q), then Q ∉ T-DSS.
 q                That being said, check whether N == Q. 

У більшості мов було б простіше зациклитися на множині натуральних чисел, знайти перші доданків -DSS (тому що цифра суми завжди не менше тому повторне додавання цього типу кількості не може призвести до значення, менше ), і перевірте, чи належить у цих перших термінах -DSS. Однак у Pyth доступні структури контрольних потоків фактично полегшують генерування термінів, поки не буде виконано певну умову, а не фіксовану кількість термінів.nk1nnnk


1
Чудово виконано, у мене було fqQ.W<HQ+sjZ1014. Я забуваю про `і s як спосіб отримання цифр з цілого числа!
Сок

3

Желе , 9 байт

DS+)i$ƬṖṪ

Монадична посилання, що приймає додатне ціле число, nяке дає додатне ціле число, a(n)зворотне колумбійське n.

Спробуйте в Інтернеті! Або дивіться тестовий набір .

Як

Ми ефективно працюємо назад, не раз шукаючи значення, яке ми додали, поки не зможемо знайти його:

DS+)i$ƬṖṪ - Link: integer n
      Ƭ   - Repeat until a fixed point, collecting up:
     $    -   last two links as a monad - f(n):
   )      -     left links as a monad for each - [g(x) for x in [1..n]]:
D         -       decimal digits of x
 S        -       sum
  +       -       add x
    i     -     first (1-indexed) index of n in that list, or 0 if no found
       Ṗ  - pop of the rightmost value (the zero)
        Ṫ - tail

Використовуючи 13як приклад ...

D  )  = [[1],[2],[3],[4],[5],[6],[7],[8],[9],[1,0],[1,1],[1,2],[1,3]]
 S    = [  1,  2,  3,  4,  5,  6,  7,  8,  9,    1,    2,    3,    4]
  +   = [  2,  4,  6,  8, 10, 12, 14, 16, 18,   11,   13,   15,   17]
    i 13 = .......................................... 11
    i 11 = .................................... 10
    i 10 = ............... 5
    i 5 = not found = 0 
    i 0 = not found = 0
    Ƭ -> [13, 11, 10, 5, 0]
    Ṗ =  [13, 11, 10, 5]
    Ṫ =               5

2

Python 2 , 85 байт

f=lambda n,a=[]:n in a and a.index(n)or f(n,[k+sum(map(int,`k`))for k in a]+[len(a)])

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

Це, безумовно, працює для всіх тестових випадків, а також усіх 1..88 записів, поданих на OEIS; але все ж я не зовсім впевнений, що це правдоподібно . (Це одна з моїх скарг на тестування Church Of Unit Testing :)).


d(x)xCi(s)isCi(0)=i;Ci(s)=Ci(s1)+Σd(Ci(s1))x>1ed(x)(e1)ed(x)(e0)Σd(x)1

S(i)Ci(S(i))=nΣd(Ci(s1))1i<inS(i),S(i)S(i)S(i)iiinia.index(n)

@Value Ink: Роджер! Це повністю працює. Спасибі!
Час Браун


2

MathGolf , 13 байт

╒môk(É∙Σ+=k/)

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

Великий виклик! Це змусило мене знайти кілька помилок у неявній поп-поведінці MathGolf, що додало 1-2 байти до рішення.

3

╒               range(1,n+1) ([1, 2, 3])
 mô             explicit map using 6 operators
   k(           push input-1 to TOS
     É          start block of length 3 (repeat input-1 times)
      ∙Σ+       triplicate TOS, take digit sum of top copy, and add that to second copy
                This transforms the array items to their respective sequences instead
                Array is now [1, 2, 4, 2, 4, 8, 3, 6, 12]
         =      get index of element in array (the index of 3 is 6)
          k/    divide by input (gives 2)
            )   increment (gives the correct answer 3)

Щоб довести, що це завжди спрацює, це легко зрозуміти n <= input, оскільки inputце перший елемент inputго послідовності. Я технічно не довів, що це рішення завжди дійсне, але воно проходить кожен тестовий випадок, який я перевірив.



1

Чисто , 86 байт

import StdEnv
$n=hd[i\\i<-[1..]|n==while((>)n)(\j=j+sum[toInt d-48\\d<-:toString j])i]

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

Розширено:

$ n                    // function `$` of `n` is
 = hd [                // the first
   i                   // integer `i`
  \\                   // for
   i <- [1..]          // each integer from 1 upwards
  |                    // where 
   n ==                // `n` is equal to
   while ((>) n) (     // the highest value not more than `n` from
    \j = j + sum [     // `j` plus the sum of
      toInt d - 48     // the digital value
     \\                // for each
      d <-: toString j // digit in the string form of `j`
     ]                 // where `j` is the previous term
    )                  // of the sequence
   i                   // starting with term `i`
  ]

Мене це турбує, що digitToInt dдовшеtoInt d-48





1

Japt , 15 14 байт

Потрійник для обробки справ, коли input=outputмене дратує!

@Ç?X±ìx:XÃøU}a

Спробуй це

@Ç?X±ìx:XÃøU}a     :Implicit input of integer U
@                  :A function taking an integer X as its argument
 Ç                 :  Map each Z in the range [0,U)
  ?                :    If Z>0
   X±              :      Increment X by
     ì             :      Convert X to digit array
      x            :      Reduce by addition
       :X          :    Else X
         Ã         :  End map
          øU       :  Contains U
            }      :End function
             a     :Return the first integer that returns true when passed through that function

1

cQuents , 18 байт

#|1:#bN;A
=A?Z+UDZ

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

Пояснення

=A?Z+UDZ      second line - helper function
               first input = A
               second input = n
=A            first term is A
  ?           mode=query, return true if n in sequence, false if n not in sequence
              each term in the sequence equals
   Z+          previous term +
     U   )                     sum (                          )
      D )                            digits (               )
       Z                                      previous term

#|1:#bN;A     main program
               first input = A  (user input)
               second input = n
#|1           n = 1
   :          mode=sequence, return the nth term in the sequence
    #     )   conditional - next term equals next N that evaluates to true
              N increments, any terms that evaluate to true are added to the sequence
               conditional (                      )
     b   )                   second line (      )
      N;A                                  N, A

1

Четвертий (gforth) , 99 байт

: f >r 0 begin 1+ dup begin dup i < while dup 20 for 10 /mod >r + r> next + repeat i = until r> . ;

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

В значній мірі схожий на подання reffu (106 байт) . Гольф-частини:

  • Розрахунок суми цифр (-6)
  • Остаточне прибирання (-1), надрукувавши трохи сміття для відстоювання. (Без проблем, оскільки результат повертається у верхній частині стека.)

Як це працює

: dsum ( n -- n+digitsum ) \ Sub-function. Given n, add its digit sum to n.
  dup                      \ Copy n to form ( n m ) -> extract digits from m and add to n
  20 for                   \ Repeat 20 times (a 64-bit int is at most 20 digits)
    10 /mod >r + r>        \   n += m%10, m = m/10
  next + ;                 \ End loop and discard 0

: f ( n -- ans )    \ Main function.
  >r                \ Move n to the return stack, so it can be referenced using `i`
  0 begin 1+        \ Initialize counter and loop starting from 1
    dup begin       \   Copy the counter (v) and loop
      dup i < while \     break if v >= n
      dsum          \     v += digit sum of v
    repeat          \   End loop
  i = until         \ End loop if n == v
  r> . ;            \ Cleanup the return stack so the function can return correctly
                    \ `r> .` is one byte shorter than `rdrop`

0

Вугілля деревне , 26 байт

NθW¬№υθ«UMυ⁺κΣκ⊞υ⊕Lυ»I⊕⌕υθ

Спробуйте в Інтернеті! Посилання на багатослівну версію коду. Використовує алгоритм @ ChasBrown Якщо це виявиться недійсним, то для 29 байт:

NθW¬№υθ«≔⊕LυηW‹ηθ≧⁺Σηη⊞υη»ILυ

Спробуйте в Інтернеті! Посилання на багатослівну версію коду. Працює, обчислюючи перший член кожної послідовності підсумовування цифр не менше ніж n. Пояснення:

Nθ

Вхідні дані n.

W¬№υθ«

Цикл, поки ми не знайдемо послідовність підсумовування цифр, що містить n.

≔⊕Lυη

Наступна послідовність починається з однієї більше, ніж кількість послідовностей поки що.

W‹ηθ

Цикл, тоді як член послідовності менше, ніж n.

≧⁺Σηη

Додайте цифру суми, щоб отримати наступного члена послідовності.

⊞υη

Висуньте остаточного члена до списку.

»ILυ

Роздрукуйте кількість обчислених списків, поки ми не знайшли такий, який містить n.




0

Гая , 16 байт

1⟨⟨:@<⟩⟨:Σ+⟩↺=⟩#

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

Повертає список, що містить найменше ціле число.

1⟨	      ⟩#	% find the first 1 positive integers where the following is truthy:
	     =		% DSS equal to the input?
  	    ↺		% while
  ⟨:@<⟩			% is less than the input
       ⟨:Σ+⟩		% add the digital sum to the counter

Гая , 16 байт

1⟨w@⟨:):Σ++⟩ₓĖ⟩#

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

Використовує спостереження, зроблені містером Xcoder . Він не коротший за інший, але все-таки цікавий підхід.

1⟨	      ⟩#	% find the first 1 integers z where:
  	     Ė		% the input (n) is an element of
  w@⟨:):Σ++⟩ₓ		% the first n terms of the z-th Digital Sum Sequence

Гая , 16 байт

┅ẋ⟨@⟨:):Σ++⟩ₓĖ⟩∆

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

Третій підхід не використовує N-find, #але все ж покладається на те саме спостереження, що і середній підхід. Повертає ціле число, а не список.


0

Clojure , 106 байт

#(loop[j 1 i 1](if(= j %)i(if(< j %)(recur(apply + j(for[c(str j)](-(int c)48)))i)(recur(inc i)(inc i)))))

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

Це 99 байт, але це призводить до переповнення стека на великих входах (можливо, налаштування JVM допоможе):

#((fn f[j i](if(= j %)i(if(< j %)(f(apply + j(for[c(str j)](-(int c)48)))i)(f(inc i)(inc i)))))1 1)



0

чорнило , 130 127 байт

-(l)
+(i)[+]->l
*(w)[{i}]
~temp n=w
-(o){n<i:
~n+=s(n)
->o
}{n>i:->w}{w}
==function s(n)
{n>9:
~return n%10+s(n/10)
}
~return n

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

  • -3 bytes шляхом перетворення на повну програму, яка потребує одинакового введення.

Це відчувається занадто довго, щоб не бути пограшком.

Безумовно

// This program takes unary input. It passes through the same choice prompt as long as it recieves 1, and execution begins when it recieves 2
-(input_loop)
+(input_value)[+] -> input_loop                 // When this option (option 1) is selected, its read count is incremented. We can access this via the "input_value" variable. We then return to the prompt by going back to the "input_loop" gather
*(which_sequence)[{i}]                          // When this option (option 2) is selected, execution begins. Its read count also serves to keep track of which DSS we're checking.
~temp current_value = which_sequence            // The initial value for the n-DSS is n, of course.
-(sequence)                                     //
{current_value < input_value:                   // If we're still below the value we're looking for, we might find it.
    ~ current_value += digit_sum(current_value) // To get the next number, we add the current number's digit sum
    -> sequence                                 // Then we loop
}
{n > i: -> which_sequence}                      // If we get here, we're at or above our target number. If we're above it, we know it's the wrong sequence and move on to the next one by going back up to option 2. This increments its read count.
{which_sequence}                                // If we get here, we've found the target number, so we output the sequence's number.
// End of main stitch, program ends.

// A function to calculate the digit sum of a number
== function digit_sum(n) ==
{n > 9: // If given a number greater than 9, recurse
    ~ return (n % 10) + digit_sum(n / 10)
}
~ return n // Otherwise, return the input (it's a single digit)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.