Унікально дешево


93

Напишіть функцію або програму, яка визначає вартість заданого рядка, де

  • вартість кожного символу дорівнює кількості, скільки разів персонаж стався до цього моменту в рядку, і
  • вартість рядка - це сума витрат його символів.

Приклад

Для входу abaacabвартість обчислюється наступним чином:

a b a a c a b
1   2 3   4    occurrence of a
  1         2  occurrence of b
        1      occurrence of c
1+1+2+3+1+4+2 = 14

Таким чином, вартість рядка abaacabстановить 14.

Правила

  • Оцінка вашого подання - це вартість вашого коду, як визначено вище , тобто подання виконується за власним вихідним кодом, нижчий бал - кращим.
  • Додавання має працювати на рядках, що містять символи ASCII для друку, а також усі символи, використані у вашій подачі.
  • Символи чутливі до регістру, тобто aі Aрізні символи.

Тестові шафи

input -> output
"abaacab" -> 14
"Programming Puzzles & Code Golf" -> 47
"" -> 0
"       " -> 28
"abcdefg" -> 7
"aA" -> 2

Таблиця лідерів


2
Як прапорці програми, такі як -nPerl, зараховуються до рахунку? Він традиційно вважається 1 байтом, оскільки відстань редагування між стандартом perl -eі perl -neдорівнює 1, але для цього виклику, чи буде nпідрахунок для підрахунку дублікатів?
Значення чорнила

2
@ValueInk Так, я думаю, що підрахунок nє найбільш справедливим варіантом.
Laikoni

1
Я дуже хочу, щоб було вирішення цього завдання.
Peter1807

10
+1 за Оцінка вашої подачі - вартість вашого коду
luizfzs

1
вартість персонажа визначається як how often this character has already occurred in the string, я б, ймовірно, змінився, щоб how many times the character has occurred up to this pointзрозуміти, що перше використання коштує 1, а не 0
підземниймонорельс

Відповіді:


83

MATL , оцінка 4

&=Rz

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

Пояснення

Розглянемо вклад 'ABBA'як приклад.

&=   % Implicit input. Matrix of all equality comparisons
     % STACK: [1 0 0 1;
               0 1 1 0;
               0 1 1 0;
               1 0 0 1]
R    % Upper triangular part
     % STACK: [1 0 0 1;
               0 1 1 0;
               0 0 1 0;
               0 0 0 1]
z    % Number of nonzeros. Implicitly display
     % STACK: 6

14
Ви професор лінійної алгебри?
Magic Octopus Urn

4
@carusocomputing Насправді професор мобільного зв’язку. Моя схильність до використання матриць походить від років програмування в Matlab
Луїс Мендо

Акуратно! Матлаб великий у цій області? Я ніколи не заглядав в GSM або щось подібне.
Чарівний восьминога Урна

2
Я приєднався до цієї спільноти лише для того, щоб похвалити вас за це геніальне рішення!
Wboy

1
@carusocomputing Matlab - це дуже поширений інструмент / мова в техніці взагалі. Це добре в чисельних обчисленнях: лінійна алгебра, обробка сигналів тощо. І як мова для інтерпретації користуватися дуже просто
Луїс Мендо

17

Пітон , оцінка 49

lambda S:sum(1+S.count(C)for[C]in	S)/2

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

Є вкладка після in.

Розбиття балів:

  • +27 на 27 унікальних знаків
  • +16 на 8 подвійних знаків: ()Camnou
  • +6 за 1 потрійний знак: S

13
Використовуйте вкладку замість пробілу, щоб зберегти байт.
mbomb007

1
@ mbomb007 Просто була така ж ідея :-)
xnor

1
@ mbomb007 Так, це геніальний трюк :-)
ETHproductions

14
@ mbomb007 це лише вкладки проти космічної війни всередині коду для гольфу
Ерік Атголфер

2
Я збирався запропонувати використовувати форму форми (що також дозволено пробілом у синтаксисі Python), але у вас більше немає простору для заміни.
user2357112

8

T-SQL, оцінка 775 579! 580

declaRe @ char(876),@x int,@v int=0Select @=q+CHAR(9)from z X:seleCT @x=len(@),@=REPLACE(@,LEFT(@,1),''),@v+=(@x-LEN(@))*(@x-LEN(@)+1)/2IF LEN(@)>0GOTO X prINT @v-1

EDIT : Випало кілька змінних, трохи ущільнилося. Вниз до 16 @символів замість 22, що само по собі знижує мою оцінку на цілих 117 балів!

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

Введення здійснюється через поле varchar q у попередньо існуючій таблиці z , згідно з нашими правилами вводу- виводу . База даних, що містить цю таблицю введення, повинна бути встановлена ​​в залежності від регістру .

Відформатовано:

declaRe @ char(876), @x int, @v int=0
Select @=q+CHAR(9)from z
X:
    seleCT @x=len(@)
          ,@=REPLACE(@,LEFT(@,1),'')
          ,@v+=(@x-LEN(@))*(@x-LEN(@)+1)/2
IF LEN(@)>0 GOTO X
prINT @v-1

Ключові слова SQL не відрізняються від регістру, тому я використовував змішаний регістр, щоб мінімізувати кількість повторюваних букв ( aaAA генерує кращий / нижчий бал, ніж aaaa ).

Основний цикл порівнює довжину до і після зняття всіх екземплярів першого символу. Ця різниця n * (n + 1) / 2 додається до поточної сумарної величини.

Функція SQL LEN()прикро ігнорує пробіли, тому мені довелося додати контрольний символ і відняти 1 в кінці.

EDIT : виправлено прорахунок мого власного бала на 2 бали (питання з цитатами), зменшений на 1, змінивши кожух на один R. Також працюючи над зовсім іншою стратегією, я буду розміщувати це як власну відповідь.


3
Спочатку я подумав, що ваш рахунок579! ≈ 8.22 x 10^1349
інженер Тост

8

C (gcc) , оцінка:  113  103 100   96  91

Дякуємо @ugoren, @CalculatorFeline, @gastropner, @ l4m2 та @ JS1 за їх поради.

g(char*s){int y[238]={};while(*s)*y-=--y[*s++];*y/=1;}

Ініціалізує масив нулів, потім використовує значення ASCII символів у рядку як індекси до цього масиву для відстеження кількості примірників кожного символу в рядку.

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


3
Пропозиція: Використовуйте імена змінних, які не використовуються в ключових словах, як z, x, c.
CalculatorFeline

@CalculatorFeline charвключає c...
Ніл

3
Крім того, вам потрібен лише масив 127 елементів ( \x7fне можна друкувати) і додайте пояснення.
CalculatorFeline

1
Пізно на вечірку, але це має бути 96:z;g(char*s){int y[238]={z=0};while(*s)z+=--y[*s++];z/=~0;}
гастропнер

1
g(char*s){int y[238]={};while(*s)*y+=--y[*s++];*y/=~0;}
l4m2

7

JavaScript (ES6), оцінка 81 78

Збережено 3 бали завдяки @Arnauld

s=>s.replace(d=/./g,z=>q+=d[z]=-~d[z],q=0)&&q

Моє оригінальне рекурсивне рішення - 81:

f=([c,...s],d={})=>c?(d[c]=-~d[c])+f(s,d):0



7

Сітківка , оцінка 34

s(O`.
M&!`^|(?<=(.))\1*
.

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

Пояснення

s(O`.

Почнемо з сортування всіх символів на вході, щоб однакові символи були згруповані в один пробіг. s(Активує SingleLine режим для всіх стадій (тобто робить .матч перекладу рядка).

M&!s`^|(?<=(.))\1*

Мета - перетворити пробіг з n символів у T n символів ( n- е трикутне число), тому що це оцінка подій цього символу. Для цього ми знаходимо сірники, що перетинаються. Зокрема, для кожного i в [1, n] ми будемо включати символи i-1 у відповідність. Усі ці поєдинки ми отримуємо через прапор, що перекривається &. Це дає нам n * (n-1) / 2 = T n-1 = T n - n символів лише із збігів. Але етап матчу приєднається до них із стрічковими стрічками, які є n рядками для nсірники. Є лише одна проблема. Після останнього матчу не буде передаватися лінійка, тому загальна кількість символів на виході на одну меншу, ніж нам потрібно. Ми виправляємо це, також узгоджуючи початок введення, що дає нам єдиний провідний канал, якщо є хоча б ще одна відповідність.

.

Нарешті, ми просто підраховуємо, скільки символів є в рядку.


6

Хаскелл, оцінка 52 51

f(a:b)=1+sum[1|c<-b,c==a]+f b;f _=0

Існує вкладка між fта _.

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

Значення порожнього рядка дорівнює 0. Значення рядка s, де aє перший знак, а bрешта рядка дорівнює 1 плюс випадки aв bплюс плюс рекурсивний виклик з b.


5

J , оцінка 16

1#.,@(*+/\"1)&=

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

Пояснення

1#.,@(*+/\"1)&=
              =  Self-classify: bit matrix of equality between input
                 and its unique elements.
     (      )&   Apply verb in parentheses to it:
       +/\         running sums
          "1       of each row
      *            multiplied with original matrix.
                 This causes the i'th 1 on each row to be replaced by i.
   ,@            Flatten the resulting matrix
1#.              and interpret as a base-1 number, computing its sum.

Використання 1#.замість +/@суми заощадило кілька балів, а &замість @монадичного контексту можна використати для збереження ще одного. Повторне 1коштувало мені однієї додаткової точки, але я не зміг її позбутися.


"пізніше" чекає чверть дня
CalculatorFeline

2
@CalculatorFeline через 10 годин ще пізніше. : P
Zgarb

Давайте зробимо це передбачуваним днем.
CalculatorFeline

Я особисто використовую цей формат для відповідей TIO, щоб відобразити точний підрахунок байтів у розділі коду, можливо, ви хочете його використати
Conor O'Brien

5

R , оцінка: 67 83 95 128

-61 завдяки найкращим порадам від Джузеппе

function(x,y=table(utf8ToInt(x)))y%*%{y+1}/2

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

Рядок розбивається за допомогою utf8ToIntі підраховується кожне значення ascii table. Результат обчислюється, використовуючи множення матриці %*%на те, що на себе + 1, і, нарешті, наполовину.


використовувати tableзамість rle; ви можете позбутися sortі цього (і вам не доведеться індексувати [[1]]результат strsplit)
Джузеппе

@Giuseppe Дякую Я навіть не думав про стіл, незабаром включу.
MickyT

2
Я думаю, ви можете зберегти ще кілька байтів, використовуючи інше ім’я змінної замість n(оскільки це в functionдва рази), а також змінивши (n+1)на{n+1}
Джузеппе,

оцінка: 67 . Деякі зміни щодо цього можуть зробити можливість зменшити бал ще більше.
Джузеппе

@Giuseppe ... Я повинен був перечитати його. whoops
MickyT


4

Pyth , оцінка 6

1 байт завдяки isaacg.

+F/V._

Тестовий набір.

Як це працює

+F/V._
+F/V._QQ  implicit input
  /V      vectorize count: for each element in the first argument,
                           count the number of occurrences of the
                           second argument:
    ._Q       all prefixes of input
       Q      input
+F        fold (reduce) on +, base case 0.

s+0те саме, що +F.
isaacg

Добре! Найкраще, що я міг би зробити, це usaShHGrScQ1 8Zза 16. Можна додати пояснення?
Цифрова травма

1
@DigitalTrauma Я додав пояснення.
Leaky Nun

s/LQце бал 4, чи використовуються в цьому функції, які вирішують виклик?
Дейв



4

C, 60 байт, оцінка 108 95

g(char*s){int y[256]={},z=0;while(*s)z-=--y[*s++];return z;}

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

Зазвичай оператори до та після збільшення чудово підходять для гольфу з кодом, але вони справді шкодять цьому виклику!

EDIT: Віднімаючи від’ємні підрахунки замість додавання позитивних, я зберег цілу купу балів. Заміна for()з while()усунена крапкою з комою , а також.



3

C # (.NET Core) , оцінка ∞ (я маю на увазі, 209)

b=>b.Distinct().Select(z=>{var w=b.Count(p=>p==z);return w*(w+1)/2;}).Sum()

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

Оцінка включає наступне:

using System.Linq;

Я знаю , що це було деякий час, але ви можете змінити , return w*(w+1)/2щоб return-~w*w/2(рахунок 196). EDIT: Ви можете створити порт моєї відповіді Java 8 для оцінки 149 : using System.Linq;b=>{int[]x=new int[256];return\nb.Select(z=>++x[z]).Sum();} Спробуйте в Інтернеті.
Кевін Кройсейсен

1
@KevinCruijssen: Я прийняв ваше рішення до оцінки 111:b=>{var x=new int[256];return\nb.Sum(z=>++x[z]);}
raznagul

@raznagul ( * піврічна відповідь, що надходить * ) 109, якщо ви зміните другий пробіл на вкладку. ;) Спробуйте в Інтернеті.
Кевін Кройсейсен

1
@KevinCruijssen (ще одна піврічна відповідь, що надходить) 49 із інтерактивним компілятором, і я думаю, що він ніколи не потрапить нижче 48. Мені здається дивним, чим більше отримують відповіді на гольф C #, тим читачішими вони завжди здаються. Спробуйте в Інтернеті!
хтось

3

Желе , оцінка 5

ĠJ€ẎS

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

Дякуємо Лікі монахині за -2 (раніше на його відповідь )


А-а-а, я не помітив цього питання досить швидко.
Лина монашка

@LeakyNun ps Ви не завжди ніндзя, і ніхто не є
Ерік Атгольфер

Дійсно? Я не думаю, що так.
CalculatorFeline


@LeakyNun Як було обіцяно ... так, заслуга є :)
Ерік Попечитель

3

PowerShell, оцінка 64

$z=@{}
$ARGS|% getE*|%{$u+=($Z.$_+=1)};$U

(Оцінка базується на єдиному новому рядку, який не є стандартним для Windows, але працює в PS).

PS C:\> D:\unique-is-cheap.ps1 (gc D:\unique-is-cheap.ps1 -raw)
64
  • Лічильник хешбелів @{}
  • Ітерація через букви; $argsє масивом параметрів - у цьому випадку рядок введення робить його масивом одного елемента; |%робить цикл foreach над елементами та використовує getE*ярлик, щоб відповідати GetEnumerator()рядковому методу та викликати його, щоб перетворити рядок у потік символів.
  • |%переведіть цикл на символи та додайте їх до хештету, додайте його до загальної кількості. ($x+=1)Форма з дужками і змінює змінну і виводить нове значення для використання.
  • Вивести поточну загальну суму.

(Коли я вперше написав це, він був $c=@{};$t=0;[char[]]"$args"|%{$c[$_]++;$t+=$c[$_]};$tз оцінкою 128, і відчув, що він не піде набагато нижче. Половина його до 64 - це дуже приємно).




3

Джулія 0,6 , 45 байт, оцінка: 77

Натхненний рішенням MATL:

f(w)=sum(UpperTriangular([z==j for z=w,j=w]))

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

Менш гарне рішення з використанням рахунків:

Юлія 0,6 , оцінка: 82

F(w)=sum(l->[l+1]l/2,count(x->x==i,w)for i=Set(w))

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

Дякуємо Guiseppe за те, що він вказав на бали та поради. Ці коментарі допомогли мені навантажити.


1
Оцінка вашого подання - це вартість вашого коду , яка, на мою думку, становить 135.
Джузеппе

1
Я не дуже добре знаю Джулію, але я думаю, що ви можете зменшити бал до 110 , змінивши імена змінних та видаливши набір дужок. Якщо повертає вектор одного елемента допускається, то ви можете замінити (x+1)з [x+1]метою подальшого зниження рахунок.
Джузеппе

Ви можете зберегти бал, змінивши другий пробіл на вкладку або новий рядок: оцінка 104 . І @Giuseppe порада використання [x+1]замість цього (x+1)знижує його до рівня 98 .
Кевін Круїссен

3

Java 10, оцінка: 149 138 137 134 133 130 103 102 101 100

( Байтів: 72 73 74 75 64 62 61 ) Байти піднімаються вгору, але оцінка знижується. : D

x->{int j=0,q[]=new int[256];for(var    C:x)j+=++q[C];return
j;}

-28 балів (і -11 байт) завдяки @Nevay .
-1 бал (і -2 байти) завдяки @ OlivierGrégoire .
-1 бал (і -1 байт), перетворивши Java 8 в Java 10.

Пояснення:

Спробуйте тут.

x->{                     // Method with character-array parameter and integer return-type
  int j=0,               //  Result-integer, starting at 0
      q[]=new int[256];  //  Integer-array with 256 times 0
  for(var   C:x)         //  Loop over the characters of the input array
    j+=++q[C];           //   Raise the value in the array by 1,
                         //   and then add it to the result-integer
  return                 //  Return 
  j;}                    //         the result

1
Ви можете видалити, ~якщо ви використовуєте j=0та return-j;(133).
Невай

1
103:x->{int[]q=new int[256];return\nx.chars().map(v->++q[v]).sum();}
Невай

1
@Nevay 103 насправді, коли я використовую jзамість u( returnмістить u) новий рядок та вкладку замість пробілів. EDIT: Хе-хе, ви редагували право, коли я зробив цей коментар. :)
Кевін Кройсейсен

3

F #, оцінка 120 118

let j z=Seq.countBy id z|>Seq.sumBy(fun x->List.sum[0..snd x])

-2 спасибі Кевіну Крейссену !

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

Приймає stringяк вхід. Seq.countByз’єднує кожен окремий персонаж з його кількістю ( idце функція ідентичності), щоб ви закінчилися з колекцією, як 'a' = 4, 'b' = 2і т.д.

Seq.sumByБере відліку для кожної букви і підсумовує все числа від 0графи для цього листа. Тож якби 'a' = 4збірка була такою, 0, 1, 2, 3, 4яка підсумована разом 10. Потім Seq.sumByпідсумовує всі ці підсумки.


2
Ви можете знизити свою оцінку на 2, змінивши let qна let j, оскільки qце вже використовується в обох Seq.
Кевін Кройсейсен

2

APL (Dyalog) , оцінка 15

+/1 1⍉+\∘.=⍨⍞

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

 отримати введення тексту

∘.=⍨ таблиця рівності з собою

+\ сукупна сума впоперек

1 1⍉ по діагоналі (освітлене згортання обох вимірів на вимір один)

+/ сума


2

Сітківка , оцінка 68 45 43

s`(.)(?<=((\1)|.)+)
$#3$*
1

Спробуйте в Інтернеті! Посилання показує бал. Редагувати: Дякуючи @MartinEnder, який врятував 20 байт, використовуючи збіги, що перекриваються замість lookaheads, та ще три байти шляхом групування етапів, так що sпрапор потрібно застосувати лише один раз. Збережено ще два байти, обчисливши трикутне число по-різному, уникаючи необхідності сортування.



2

Perl 5 оцінка 91 83

Використовується -pпрапор, який додає 2 через p в роздвоєнні.

$x=$_;$b+=++$a{$_}for(split//,$x);$_=$b

Ласкаво просимо до PPCG!
Лайконі

1
Скориставшись вашою відповіддю як базою та застосувавши деякі прийоми на сторінці підказок, мені вдалося звести ваш результат до 31: Спробуйте в Інтернеті! . $` is automatically print ed after each call so we can use that to store the score and /./ g` повертає список усіх символів $_, який дешевший, ніж split//.
Дом Гастінгс

Я знаю, що це старе завдання, але ви можете зменшити рахунок ще більше: Спробуйте в Інтернеті!
Xcali

2

Октава , 39 байт, оцінка 69

@(a)sum((b=hist(a,unique(1*a))).^2+b)/2

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

Хоча є ще одна відповідь Октави, ця цілком моя і інша підхід, плюс вона набирає менше :).

Підхід зводиться до першого пошуку кількості (b) кожного унікального символу, що досягається за допомогою функції гістограми. Потім для кожного елемента обчислюємо суму від 1 до b, яка робиться за формулою (b*(b+1))/2. Потім окремі суми підсумовуються до підсумкової оцінки.

Під час тестування здається, що дужки дійсно дорого коштують, оскільки їх потрібно багато. Я оптимізував початковий бал приблизно 88, переставляючи питання, щоб мінімізувати кількість відкритих / закритих дужок - отже, тепер ми робимо / 2 на остаточному підсумку, а не окремо, а також я змінив формулу на (b^2+b)/2як для цього потрібно менше дужок.


1
На жаль, це виявляється невдалим у порожній рядку:error: hist: subscript indices must be either positive integers less than 2^31 or logicals
Laikoni

2

Звичайний Лісп, оцінка 286 232 222

(loop with w =(fill(make-list 128)0)as z across(read)sum(incf(elt w(char-code z))))

Висока оцінка за рахунок багатослівного синтаксису вбудованих операторів Common Lisp.

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

Невикористаний код:

(loop with w = (fill (make-list 128) 0)  ; create a list to count characters
   as z across (read)                   ; for each character of input
   sum (incf (elt w (char-code z))))     ; increase count in list and sum

2

Математика, оцінка 54

Total[#(#+1)/2&@Counts@Characters@#]&

вхід

["abcdefg"]

завдяки hftf


Total[#(#+1)/2&@Counts@Characters@#]&оцінка 54.
hftf
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.