Не совсем римская троица


23

Если задано целое число n ≥ 0, выведите его в непозиционной записи base-3, используя цифры 139ABCDE…и разделитель из 1 символа. Каждая цифра является последовательной степенью 3, а цифры на левой стороне разделителя обнуляются , например, A931 | B → 81– (1 + 3 + 9 + 27) → 41 . Цифра может появиться только один раз.

Строго говоря, пусть значение цифры будет:

  • его значение, если цифра 1, 3 или 9
  • 27, если цифра A
  • 3 раза значение цифры прямо перед ней для B..Z

Ваш вывод должен удовлетворять sum (значение цифр справа от |) - sum (значение цифр слева от |) == input .

Примеры

input     output
----------------
0         |
1         |1
7         3|91
730       |D1
9999      FEDC|GA9

Вы можете использовать другой непробельный символ в качестве разделителя. Вам также разрешено не иметь разделителя, и в этом случае наибольшая цифра начинает положительную последовательность. Вам не нужно обрабатывать что-либо больше, чем 2 32 -1 ( PMIGDCBA9|RQNLH3).

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

Это , поэтому чем короче ваш ответ, тем лучше!


2
(связано не означает дубликат, успокойся)
Leaky Nun

8
Я единственный, кто не имеет ни малейшего понятия, о чем здесь говорят?
Лохматый

3
@ Shaggy Выразите входные данные в виде суммы степеней 3 и их негативов. Положите негативы слева от |а позитивы справа от него.
Мартин Эндер

2
@KevinCruijssen "нет, заказ бесплатный." - OP
user202729

3
@ user202729 Ах, пропустил этот комментарий. Спасибо. Вот что происходит, когда правила в комментариях вместо того, чтобы редактировать их в задании . ( FrownyFrog , не могли бы вы добавить это правило в задание : любой порядок по обе стороны от разделителя в порядке?)
Кевин Круйссен,

Ответы:


5

Java 10, 120 113 112 109 107 102 байта

n->{var r="|";for(char c=49;n++>0;c=(char)(c+=c>64?1:c*4%22%9),n/=3)r=n%3<1?c+r:n%3>1?r+c:r;return r;}

-3 байта, используя часть хитрости ответа @Arnauld 's JavaScript (ES6) ,
изменяя i=0и i++<1?49:i<3?51:i<4?57:i+61на i=4и ++i>9?i+55:i>8?57:++i+43.
-6 байт благодаря @Arnauld напрямую, избавившись от i.

Порядок вывода: от наивысшего к низшему, |-делимитер, от низшего к высшему.

Объяснение:

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

n->{              // Method with integer parameter and String return-type
  var r="|";      //  Result-String, starting at the delimiter "|"
  for(char c=49;  //  Character, starting at '1'
      n++>0       //  Loop as long as `n` is larger than 0
                  //  Increasing it by 1 with `n++` at the start of every iteration
      ;           //    After every iteration:
       c=(char)(  //     Change character `c` to:
          c+=c>64?//      If the current `c` is an uppercase letter:
              1   //       Simpy go to the next letter using `c+1`
             :    //      Else:
              c*4%22%9),
                  //       Change '1' to '3', '3' to '9', or '9' to 'A' 
       n/=3)      //     Integer-divide `n` by 3
     r=           //     Change the result to:
       n%3<1?     //      If `n` modulo-3 is 0:
        c+r       //       Prepend the character to the result
       :n%3>1?    //      Else-if `n` modulo-3 is 2:
        r+c       //       Append the character to the result
       :          //      Else:
        r;        //       Leave `r` unchanged
   return r;}     //  Return the result-String

1
Я думаю, что это работает: 103 байта
Арно

@Arnauld Хороший! И еще -1 байт, помещая rв тело цикла. Благодарность!
Кевин Круйссен

@Arnauld Из любопытства, как выглядят брутфорсеры, которых вы использовали для этих двух последних магических чисел (когда вы все еще использовали iи когда вы снова использовали c)?
Кевин Круйссен

1
Я уже выбросил это ...: / / Но вот последний . (Очень неэффективно, но это нормально для таких малых значений.)
Арно

(Кроме того, мне действительно следует проверить, есть ли в коде код, если он есть , p=1и не включать *1его, хотя это и не приводит к лучшей формуле в этом случае.)
Арно 27


5

JavaScript (ES6), 82 80 79 байт

Вывод в нижнем регистре, который, надеюсь, будет в порядке.

f=(n,s=(k=4,'|'),c=++k>8?k.toString(36):++k-5)=>n?f(++n/3|0,[c+s,s,s+c][n%3]):s

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

Похоже на ответ прохудшего «Мастера ниндзя», а также на основе ответа xnor .

Цифровое преобразование

Начнем с к = 4 . Хотя k меньше 9 , мы увеличиваем его дважды на каждой итерации и вычитаем 5 . После этого мы увеличиваем его только один раз и конвертируем в base-36.

  k  | ++k > 8       | k.toString(36) | ++k - 5  | result
-----+---------------+----------------+----------+--------
  4  | k=5  -> false |                | k=6 -> 1 | 1
  6  | k=7  -> false |                | k=8 -> 3 | 3
  8  | k=9  -> true  | '9'            |          | '9'
  9  | k=10 -> true  | 'a'            |          | 'a'
  10 | k=11 -> true  | 'b'            |          | 'b'
 ... | ...           | ...            | ...      | ...



2

Stax , 30 29 байт

£└≤☻╘pÿ╖╡A[ô%æτ⌐}►ºôßHl4⌡π%^ 

Запустите и отладьте его

Порт моего Stax ответа в Balanced Ternary Converter .

объяснение

Использует распакованную версию для объяснения.

139$VA+cz{;3%+,^3/~;wY1|I@'|ay2|I@L
139$VA+c                               "139AB...Z", make a copy
        z                              Empty array to store the digits
          {         w                  Do the following until 0.
           ;3%+                           Append `b%3` to the digits
                                          Originally, `b` is the input
              ,^3/                        `b=(b+1)/3`
                  ~;                       Make a copy of `b` which is used as the condition for the loop

                     Y                 Save array of digits in `y` for later use
                      1|I              Find index of 1's
                         @             Find the characters in "139AB...Z" corresponding to those indices
                          '|           A bar
                            ay2|I@     Do the same for 2's
                                  L    Join the two strings and the bar and implicit output

1

C # .NET, 103 байта

n=>{var r="|";for(var c='1';n++>0;c=(char)(c>64?c+1:c+c*4%22%9),n/=3)r=n%3<1?c+r:n%3>1?r+c:r;return r;}

Порт моего Java 10 ответа . Если бы был возможен прямой порт (кроме n->to n=>), я бы отредактировал свой ответ на Java с помощью этого полиглота. К сожалению, однако, c+=на символах или не иметь c=49возможности в C #, следовательно, этот свободный портированный ответ.

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


1

Perl 5 -p , 71 69 байт

не использует разделитель. Отрицательные и положительные части находятся в «римском порядке» (наибольшая цифра первая)

#!/usr/bin/perl -p
$n=$_}{s/@{[$n++%3]}\K/]/,$n/=3,y/?-]/>-]/for($_=21)x31;y/>?@12/139/d

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


1

Рубин , 87 84 82 байта

Сохранено 2 байта благодаря @ benj2240.

->n,s=[?1,?3,?9,*?A..?Z],r=[""]*3{r[-m=n%3]+=s.shift
n=n/3+m/2
n>0?redo:r[1,2]*?|}

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


Я бы соврал, если бы сказал, что полностью следую этому коду, но я точно знаю, что вы сбрили 2 байта с redoхитростью: попробуйте онлайн!
benj2240

1

J , 129 байт

f=:3 :0
a=.'139',u:65+i.26
s=.'|'while.y>0 do.if.1=c=.3|y do.s=.s,{.a end.y=.<.y%3
if.c=2 do.s=.s,~{.a 
y=.1+y end.a=.}.a end.s
)

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

Слишком долго, особенно для программы J ...

Объяснение:

f =: 3 : 0
   a =. '139',u:65+i.26   NB. a list '139ABC...Z'
   s =. '|'               NB. initialize the list for the result  
   while. y>0 do.         NB. while the number is greater than 0
      c =. 3|y            NB. find the remainder (the number modulo 3)
      y =. <.y%3          NB. divide the number by 3 
      if. c = 1 do.       NB. if the remainder equals 1
         s =. s,{.a       NB. Append the current power of 3 to the result
      end.
      if. c = 2 do.       NB. if the remainder equals 2 
         s =. s,~{.a      NB. prepends the result with the current power of 3
         y =. 1+y         NB. and increase the number with 1
      end.
      a =. }.a            NB. next power of 3 
   end.
   s                      NB. return the result  
)

1

C int: 138 123 байта long: 152 131 байта

Я создал две версии этого, так как предел трудностей при максимальном рабочем входе 0x100000000казался немного странным. Одна версия работает с 32-битными целыми числами (что по понятным причинам выходит за пределы ограничения), другая версия работает с 64-битными значениями (что выходит за рамки заданного ограничения за счет 14 8 дополнительных байтов).

32-битная версия:

char b[22],*r=b;f(v,l)char*l;{v%3>1?*r++=*l,v++:0;v&&f(v/3,l+1);v%3?*r++=*l:0;}g(v){f(v,"139ABCDEFGHIJKLMNOPQR");*r=0;r=b;}

64-битная версия:

char b[22],*r=b;f(long v,char*l){v%3>1?*r++=*l,v++:0;v&&f(v/3,l+1);v%3?*r++=*l:0;}g(long v){f(v,"139ABCDEFGHIJKLMNOPQR");*r=0;r=b;}

Это идентично, за исключением того, что оно объявляет целочисленную переменную long(которая в Linux равна 64 битам).

Негольфированная longверсия:

char buffer[22],*result=buffer;
f(long value,char*letter){
    if(value%3>1){
        *result++=*letter,value++;
    }
    if(value){
        f(value/3,letter+1);
    }
    if(value%3){
        *result++=*letter;
    }
}
g(long value){
    f(value,"139ABCDEFGHIJKLMNOPQR");
    *result=0;
    result=buffer;
}

Как вы можете видеть, это работает по принципу рекурсивного приличия: если остаток равен 1, соответствующий символ добавляется к выходной строке после рекурсивного вызова. Если остаток равен 2, вывод выполняется перед рекурсией. В этом случае я также увеличиваю значение на единицу, чтобы правильно обрабатывать отрицательную цифру. Это имеет дополнительное преимущество, заключающееся в изменении остатка на ноль, что позволяет мне использовать его value%3как условие для пострекурсии if.

Результат преобразования помещается в глобальный буфер. g()Обертка имеет работу нуля завершающие получившуюся строку правильно, и чтобы сбросить resultуказатель на его начало (что и как g()«возвращает» результат).

Проверьте long версию с этим кодом:

#include <stdio.h>

char b[22],*r=b;f(long v,char*l){v%3>1?*r++=*l,v++:0;v&&f(v/3,l+1);v%3?*r++=*l:0;}g(long v){f(v,"139ABCDEFGHIJKLMNOPQR");*r=0;r=b;}

void printConversion(long value) {
    g(value);
    printf("%ld: %s\n", value, r);
}

int main() {
    for(long i = 0; i <= 40; i++) {
        printConversion(i);
    }
    printConversion(0x7fffffff);
    printConversion(0xffffffffu);
    printConversion(0x100000000);
}

Возможно дальнейшее, но деструктивное гольфирование:

  • -4 байта: сделать функцию однократной, удалив сброс указателя в g() .

  • -5 байт: заставить вызывающего выполнить завершение строки, возвращая строку без завершения в bufferи конец строки в result.


1

Древесный уголь , 36 байт

NθF³⊞υ⟦⟧F⁺139α«⊞§υθι≔÷⊕θ³θ»F²«×|ι↑⊟υ

Попробуйте онлайн! Ссылка на подробную версию кода. Объяснение:

Nθ

Введите значение.

F³⊞υ⟦⟧

Переместите три пустых списка в предварительно определенный пустой список.

F⁺139α«

Переберите символы 139и заглавные буквы.

⊞§υθι

Циклически индексируйте список списков со значением и вставляйте в него текущий символ.

≔÷⊕θ³θ»

Разделите значение на 3, но округлите его, сначала добавив 1.

F²«×|ι

Цикл дважды. Второй раз выведите a |.

↑⊟υ

В каждом цикле мы выскакиваем последнюю запись из списка; в первый раз это дает нам записи, у которых есть остаток от 2(который соответствует сбалансированной троичной цифре -1), в то время как во второй раз это дает нам записи, соответствующие сбалансированной троичной цифре в 1. Результирующий массив обычно печатается вертикально, но поворот направления печати вверх отменяет это.



0

Perl 5 , 92 89 байт

Вдохновленный ответами Java и Python.

sub n{($n,$r,$c,@a)=(@_,'|',1,3,9,'A'..'Z');$n?n(int++$n/3,($c.$r,$r,$r.$c)[$n%3],@a):$r}

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

С некоторым пробелом:

sub n {
  ($n, $r, $c, @_) = (@_, "|", 1, 3, 9, 'A' .. 'Z');
  $n ? n( int++$n/3, ($c.$r, $r, $r.$c)[$n%3], @_)
     : $r
}

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.