Суми підміни знаків


24

Враховуючи непорожній список натуральних чисел , ваше завдання - визначити кількість унікальних значень(x,y,z,)±x±y±z±

Наприклад, розглянемо список . Існує вісім можливих способів створення сум:(1,2,2)

  • +1+2+2+5
  • +1+22+1
  • +12+2+1
  • +1223
  • 1+2+2+3
  • 1+221
  • 12+21
  • 1225

Є шість унікальних сум , тому відповідь - .6{5,5,1,1,3,3}6

Випробування

[1, 2] => 4
[1, 2, 2] => 6
[s]*n => n+1
[1, 2, 27] => 8
[1, 2, 3, 4, 5, 6, 7] => 29
[3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5] => 45
[1, 7, 2, 8, 3, 1, 6, 8, 10, 9] => 56
[93, 28, 92, 100, 43, 66, 2, 98, 2, 52, 57, 75, 39, 77, 45, 15, 13, 82, 81, 20, 68, 14, 5, 3, 72, 56, 57, 1, 23, 25, 76, 59, 60, 71, 71, 24, 1, 3, 72, 84, 72, 28, 83, 62, 66, 45, 21, 28, 49, 57, 70, 3, 44, 47, 1, 54, 53, 56, 36, 20, 99, 9, 89, 74, 1, 14, 68, 47, 99, 61, 46, 26, 69, 21, 20, 82, 23, 39, 50, 58, 24, 22, 48, 32, 30, 11, 11, 48, 90, 44, 47, 90, 61, 86, 72, 20, 56, 6, 55, 59] => 4728

Довідкове рішення (оптимізує швидкість, а не розмір).

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

Оцінка балів

Це , тому найкоротше діюче рішення (вимірюється в байтах) виграє.


Чи потрібно обробляти випадок, коли вхід - це порожній масив?
Час Браун

@ChasBrown вхід не порожній, відповідно до публікації.
JungHwan Min

Гм, я не можу зрозуміти, як працює третій тестовий випадок, будь ласка, будь ласка, поясніть?
Ерік Аутгольфер

@EriktheOutgolfer Це ефективно говорить, якщо ваш масив є однаковими числами (наприклад [2,2,2,2,...]), відповідь повинна бути довжиною масиву + 1. Це тому, що в цьому випадку позиція знаків не має значення і лише кількість кожного питання
reffu

@reffu Це скоріше жарт, він виглядає якось так, ніби він був включений туди помилково.
Ерік Аутгольфер

Відповіді:


13

Мова Вольфрама (Mathematica) , 27 байт

Tr[1^Fold[#⋃+##&,{0},#]]&

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

Визначення кількості унікальних сум для заміни знаків рівнозначно пошуку кількості унікальних сум підмножини.

Доказ передбачає додавання суми вхідних даних до кожної суми заміни знаків і ділення на два. Тоді, явна біекція.

Пояснення

Fold[#⋃+##&,{0},#]

Ітерація через вхід, початковим значенням якого є {0}: взяти об'єднання між <current value>та <current value> + input element( відобразити на списки).

Tr[1^ ... ]

Голфі-версія Lengthфункції.


8

Желе , 6 байт

ŒPS€QL

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

Фон

Нехай L - вхідний список, а {P, N} розділ на алгебраїчні зведення з позитивними та негативними ознаками. Специфікація виклику вимагає обчислення s {P, N} = sum (P) - sum (N) .

Однак, оскільки сума (P) + сума (N) = сума (L) і сума (L) не залежить від розділу, маємо s {P, N} = sum (P) - sum (N) = sum ( Р) - (сума (L) - сума (P)) = 2sum (P) - сума (L) .

Таким чином, кожне унікальне значення суми (P) відповідає одному унікальному значенню s {P, N} .

Як це працює

ŒPS€QL  Main link. Argument: A (array)

ŒP      Powerset; generate all subarrays of A.
  S€    Take the sum of each.
    Q   Unique; deduplicate the sums.
     L  Take the length.

7

MATL , 11 10 байт

nW:qBGY*un

Спробуйте в Інтернеті! Це порт відповіді Октава / MATLAB Луїса Мендо . Я все ще намагаюся вивчити MATL, і я подумав, що опублікую його разом із поясненням, оскільки MATL - це мова місяця.

Пояснення:

Ось ознайомлення для тих, хто незнайомий із програмуванням на основі стека взагалі та MATL зокрема.

Вхідний вектор неявно розміщується на стеці. Зауважте, що коли операція виконується на елементі в стеку, цей елемент видаляється зі стека.

                % Stack:
                % [1, 2, 2]
n               % Counts the number of elements of the vector on the top of the stack.
                % Stack:
                % [3]
 W              % Raise 2^x, where x is the number above it in the stack
                % Stack:
                % [8]
  :             % Range from 1...x, where x is the number above it in the stack.                    % Stack:
                % [1, 2, 3, 4, 5, 6, 7, 8]
   q            % Decrement. Stack:
                % [0, 1, 2, 3, 4, 5, 6, 7]
    B           % Convert to binary. Stack:
                % [0,0,0; 0,0,1; 0,1,0; 0,1,1; 1,0,0; 1,0,1; 1,1,0; 1,1,1] 
     G          % Push input again. Stack:           
                % [0,0,0; 0,0,1; 0,1,0; 0,1,1; 1,0,0; 1,0,1; 1,1,0; 1,1,1], [1; 2; 2]
      Y*        % Matrix multiplication of the two elements on the stack.
                % Stack:
                % [0; 2; 2; 4; 1; 3; 3; 5]
        u       % Keep only unique elements. Stack:
                % [0; 2; 4; 1; 3; 5]
         n      % Number of elements in the vector. Stack:
                % [6]

І тоді він виводить остаточний елемент на стек неявно.


1
Приємне пояснення!
Луїс Мендо


6

Python 2 , 52 байти

k=1
for n in input():k|=k<<n
print bin(k).count('1')

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

Використовує двійкове представлення числа для зберігання доступних сум підмножини.


1
Чи можете ви пояснити, як це працює? Ви самі це придумали, чи це якийсь відомий результат?
sundar

1
@sundar Це не так складно. Ця відповідь обчислює унікальні суми (не заміни знаків), як і багато інших відповідей. Кожен біт у k відповідає сумі. k<<nдодає n до кожної суми. Або kзберігання цих нових сум k, зберігаючи всі попередні, а дублюються
симси

Ах, слід руйнування веде назад до ідеї біекціонування Юнгвану Міна , це було головне розуміння, про яке я бракував . Тут кожна сума підмножини представлена ​​значком 1 у цій позиції в бітовому рядку (з початковим 1 у LSB, що представляє суму 0 для порожнього підмножини). Я все-таки не те, що я б назвав "не таким складним", але це може бути просто моїм недосвідченим словом. :)
sundar


5

Haskell, 46 байт

import Data.List
length.nub.map sum.mapM(:[0])

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

Замість того, щоб підсумовувати підмножини списку введення, ми робимо всі комбінації або збереження числа, або заміни його на 0, наприклад

mapM(:[0])[1,2,3] -> [[1,2,3],[1,2,0],[1,0,3],[1,0,0],[0,2,3],[0,2,0],[0,0,3],[0,0,0]]

Це на два байти коротше subsequences.


Гарна відповідь! Я сподівався, що щось на кшталт f x=sum[1|i<-[0..sum x],elem i$sum<$>mapM(:[0])x]буде коротшим, ніж імпорт, але, мабуть, це не так.
Лінн

Приємно, навіть коротше, ніж переклад "Математики", хоча я вважаю, що це красивіше:import Data.List;length.foldr((<*>)union.map.(+))[0]
Джон Перді,

5

R, 83 75 байт

-8 байт завдяки JayCe та Джузеппе

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

function(v)nrow(unique(t(t(expand.grid(rep(list(c(1,-1)),sum(v|1)))))%*%v))


попередня версія:

f=function(v)nrow(unique(as.matrix(expand.grid(rep(list(c(1,-1)),length(v))))%*%v))

Безголовка з коментарями:

f=function(vector){

  List=rep(list(c(1,-1)),length(vector))   ## Create a list with length(vector) elements, all (1,-1)

  Combinations=expand.grid(Length)    ## get all combinations of the elements of the list, e.g, 1,-1,1,1,-1,1

  Matrix=as.matrix(Combinations)   ## convert to matrix

  Results=Matrix%*%vector   ## multiply the matrix original vector to get a Nx1 matrix

  Unique_results=unique(Results)   ## unique the results

  nrow(Unique_results)   ## length = number of rows of unique values
  }

Збережіть кілька байтів за допомогою t: TIO
JayCe

і sum(v|1)є байтом коротшим заlength(v)
Джузеппе

4

Октава / MATLAB, 45 41 40 байт

@(x)nnz(unique(dec2bin(0:2^nnz(x)-1)*x))

Вхід - вектор стовпця (використовується ;як роздільник).

Помилки коду для останнього тестового випадку через обмеження пам'яті.

Для цього використовується ідея відповіді JungHwan Min (підмножини замість чергування знаків), щоб зберегти кілька байт.

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



3

Python 3 , 61 байт

f=lambda a,s={0}:a and f(a[1:],s|{u+a[0]for u in s})or len(s)

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

Рекурсивний підхід, відстежуючи унікальні суми підмножини.

Справжня забава полягає в тому, що це б'є itertoolsз великим відривом:

76 байт

lambda a:len({*map(sum,product(*([0,x]for x in a)))})
from itertools import*

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



3

Attache , 29 байт

{#Unique[Flat!±_]}@Fold[`±]

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

Це працює, склавши ±оператор над вхідним списком, потім взявши ±цей список, а потім підрахувавши унікальні атоми масиву.

Ось кілька прикладів того, як працює складання:

Fold[`±][ [1,2] ] == 1 ± 2
                  == [1 + 2, 1 - 2]
                  == [3, -1]
Fold[`±][ [1,2,2] ] == (1 ± 2) ± 2
                    == [3, -1] ± 2
                    == [[3 + 2, 3 - 2], [-1 + 2, -1 - 2]]
                    == [[5, 1], [1, -3]]
                    == [5, 1, 1, -3]
Fold[`±][ [4,4,4,4] ] == (4 ± 4) ± 4 ± 4
                      == [8, 0] ± 4 ± 4
                      == [[12, 4], [4, -4]] ± 4
                      == [[[16, 8], [8, 0]], [[8, 0], [0, -8]]]
                      == [16, 8, 8, 0, 8, 0, 0, -8]
                      == [16, 8, 0, -8]

Потім ми генеруємо всі перестановки остаточного знаку, застосовуючи PlusMinus ще раз.

Більш ефективна версія, 31 байт

`#@(q:=Unique@Flat@`±)@Fold[q]

Спробуйте в Інтернеті! Це не вичерпується в остаточному тестовому випадку, оскільки не створює зайвих комбінацій.


3

R , 62 байти

function(V)sum(unique(c(V%*%combn(rep(0:1,L),L<-sum(V|1))))|1)

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

Алгоритм порту Денніса. Він найближчий до відповідей Octave / MATL, оскільки він використовує аналогічний растровий і матричний продукт для включення / виключення термінів.







2

Утиліти Bash + GNU, 49 байт

eval echo "{,-}${@//,/{+,-\}}\;"|bc|sort -u|wc -l

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

Введення подано у списку, розділеному комами, у командному рядку.

Пояснення

               ${@//,/{+,-\}}                      # Replace commas with {+,-}
          "{,-}${@//,/{+,-\}}\;"                   # Build a brace expansion with {+,-} before every number and ; at the end
eval echo "{,-}${@//,/{+,-\}}\;"                   # Expand to give every combination expression, separated by ;
                                |bc                # Arithmetically evaluate each line
                                   |sort -u        # Remove duplicates
                                            wc -l  # Count

2

x86_64 машинна мова для Linux, 31 29 байт

 0:   31 d2                   xor    %edx,%edx
 2:   6a 01                   pushq  $0x1
 4:   58                      pop    %rax
 5:   8b 0c 97                mov    (%rdi,%rdx,4),%ecx
 8:   48 89 c3                mov    %rax,%rbx
 b:   ff c2                   inc    %edx
 d:   48 d3 e3                shl    %cl,%rbx
10:   48 09 d8                or     %rbx,%rax
13:   39 d6                   cmp    %ese,%edx
15:   7c ee                   jle    5 <+0x5>
17:   f3 48 0f b8 c0          popcnt %rax,%rax
1c:   c3                      retq

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

Натхненний відповіддю @ xnor. Потрібна машина з POPCNTінструкцією.




1

Чисто , 82 байти

import StdEnv
f[]=length
f[h:t]=f t o foldr(\e l=removeDup[e+h,e-h:l])[]
?l=f l[0]

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

Визначає функцію, яка ? :: [Int] -> Intвикористовує f :: [Int] -> ([Int] -> Int)як помічник для зменшення на кожну можливу суму після додавання чи віднімання.


Ось гольф-версія довідкового рішення в Haskell; не впевнений, скільки він може перенести на Clean, але ви можете отримати щось із цього.
Esolanging Fruit

@EsolangingFruit Дякую, але він вже використовує той самий підхід, і я не можу знайти спосіб скоротити його, навіть за допомогою еталонного рішення.
Οurous

1

APL (Dyalog Classic) , 21 байт

⍴∘∪⊢+.×1-2×2(⍴⍨⊤∘⍳*)⍴

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

Пояснення

2(⍴⍨⊤∘⍳*)⍴

Функціональний поїзд, еквівалентний {((⍴⍵)⍴2)⊤⍳(⍴⍵)}, який генерує матрицю, яка має двійкові представлення від 0 до довжини введення у вигляді стовпців

1-2×

Карти 1s до -1s та 0s до 1s

⊢+.×

Матричне множення на вхід, який дає масив усіх можливих сум

⍴∘∪

Видаліть дублікати, а потім порахуйте


1

Java 8, 207 83 44 байт

s->Long.bitCount(s.reduce(1L,(r,c)->r|r<<c))

Порт відповіді Python 2 @ xnor .
-39 байт завдяки @Jakob .

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

s->               // Method with Long-Stream parameter and long return-type
  Long.bitCount(  //  Return the amount of 1s in the binary representation of:
    s.reduce(1L,  //   Result-Long, starting at 1
     (r,c)->      //   Loop pair-wise (result,current):
      r|          //    Bitwise-OR the result `r` with:
        r<<c))    //    result `r` bitwise left-shifted by the current `c`

2
44 байти - це все, що нам потрібно! Беручи потік Long: s->Long.bitCount(s.reduce(1l,(a,e)->a|a<<e)).
Якоб

@Jakob Дякую! Я завжди забуваю про це .reduce.bitCountтакож можу додати ..>.>) -39 байт прямо там! :)
Кевін Круїйсен

1
Також я просто зробив версію з довільною точністю . Схоже, найдешевший спосіб зробити це все-таки з растровою картою, а не з наборами.
Якоб

1

Java 8, 85 байт

Інший Java порт XNOR відповіді «s . Як і в оригінальній відповіді, тут використовується растрова карта з довільною точністю, щоб не було верхньої межі розміру суми підмножини.

Це лямбда від послідовного java.util.stream.Stream<Integer>до int.

s->s.reduce(java.math.BigInteger.ONE,(a,e)->a.or(a.shiftLeft(e)),(u,v)->u).bitCount()

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

Зауважте, що комбінатор (третій аргумент до reduce) не використовується, оскільки потік є послідовним. Я вибрав функцію довільну.


1

Джулія 0,6 , 54 52 байти

V->(~W=W==[]?0:∪([n=W[] -n].+~W[2:end]))(V)|>endof

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

( -2 байт, замінюючи ¬з ~, завдяки Джо Кінг )

Працює для всіх тестових випадків. Використовує мовлення для збору всіх можливих сум, а потім підраховує їх.

Пояснення:

function g_(V)
  function inner(W)  #named ~ in golf version to save bytes
    W == [] ? 0 :    #return 0 when input empty (base case)
    ∪(               #unique elements of
      [n=W[] -n]     #take the first element and its negation
      .+             #broadcast-add that to each element of
      inner([2:end]) #sign-swapping sums of the rest of the array
     )
  end                #returns the list of unique elements out of those sums
  return endof(inner(V)) #return the length of that list
end

Старіше рішення:

Джулія 0,6 , 64 байти

N->endof(∪([2(i&2^~-j>0)-1 for i=0:~-2^(l=endof(N)),j=1:l]*N))

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

Працює для вхідних масивів довжиною до 63 (тому не працює для останнього тестового випадку, що є нормальним згідно з ОП).

Пояснення:

function f_(N)
  endof(                            #length of
        ∪(                          #unique elements of
          [
           (i & 2^(j-1) > 0)        #check j'th bit (from right) of i
           * 2 - 1                  #convert bit value from (0,1)=>(-1,1)
           for i = 0:2^endof(N)-1,  #where i is numbers 0 to 2^length(N)-1
           j = 1:endof(N)           #and j is 1 to length(N) (i.e. the bits in i)
          ]                         #so we have a matrix [-1 -1 -1;1 -1 -1;1 -1 1;...]
          *                         #matrix multiply that with the input array, 
          N                         #thus calculating different combinations of 
         ))                         #sign-swapping sums
end

0

JavaScript (Babel Node) , 64 байти

F=([f,...r],s=[0])=>f?F(r,s.flatMap(x=>[x+f,x])):new Set(s).size

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

Це не працюватиме для останнього тесту.


Більш ефективне рішення (працює над останньою тестовою шкалою):

JavaScript (Babel Node) , 71 байт

F=([f,...r],s=[0])=>f?F(r,[...new Set(s.flatMap(x=>[x+f,x]))]):s.length

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


Це не працюватиме в реальному браузері через Array#smoosh.

Завдяки Bubbler, [x+f,x-f]-> [x+f,x]зберігає 2 байти.


Ви можете використовувати [x+f,x]замість [x+f,x-f]( доказ JungHwan Min ).
Бубон

+2 байти для версії ES6:F=([f,...r],s=[0])=>f?F(r,[...s,...s.map(x=>x+f)]):new Set(s).size
Ніл

@Neil, і ... [...s,...s.map(x=>x+f)], s.concat(s.map(x=>x+f))і, поділяй s,s.map(x=>s.push(x+f))однакову довжину ...
tsh

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