Сівер сортувати масив


44

Виклик

Дано не порожній масив цілих чисел, наприклад:

[5, 2, 7, 6, 4, 1, 3]

Спочатку розділіть його на масиви, де жоден елемент не перевищує попередній (тобто масив, що не збільшується):

[5, 2] [7, 6, 4, 1] [3]

Далі, переверніть кожен масив:

[2, 5] [1, 4, 6, 7] [3]

Нарешті, об'єднайте їх усіх разом:

[2, 5, 1, 4, 6, 7, 3]

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

Правила

  • Введення та вихід можуть бути надані будь-якими стандартними методами та можуть бути у будь-якому розумному форматі масиву.
  • Вхідний масив ніколи не буде порожнім, але може містити негативи та / або дублікати.
  • Абсолютне значення кожного цілого числа завжди буде менше 2 31 .

Тестові справи

Сподіваємось, вони охоплюють усі крайові справи:

[1] -> [1]
[1, 1] -> [1, 1]
[1, 2] -> [1, 2]
[2, 1] -> [1, 2]
[2, 3, 1] -> [2, 1, 3]
[2, 1, 3] -> [1, 2, 3]
[2, 1, 2] -> [1, 2, 2]
[2, 1, 1] -> [1, 1, 2]
[3, 1, 1, 2] -> [1, 1, 3, 2]
[3, 2, 1, 2] -> [1, 2, 3, 2]
[3, 1, 2, 2] -> [1, 3, 2, 2]
[1, 3, 2, 2] -> [1, 2, 2, 3]
[1, 0, 5, -234] -> [0, 1, -234, 5]
[1, 0, 1, 0, 1] -> [0, 1, 0, 1, 1]
[1, 2, 3, 4, 5] -> [1, 2, 3, 4, 5]
[5, 4, 3, 2, 1] -> [1, 2, 3, 4, 5]
[2, 1, 5, 4, 3] -> [1, 2, 3, 4, 5]
[2, 3, 1, 5, 4] -> [2, 1, 3, 4, 5]
[5, 1, 4, 2, 3] -> [1, 5, 2, 4, 3]
[5, 2, 7, 6, 4, 1, 3] -> [2, 5, 1, 4, 6, 7, 3]
[-5, -2, -7, -6, -4, -1, -3] -> [-5, -7, -2, -6, -4, -3, -1]
[14, 5, 3, 8, 15, 7, 4, 19, 12, 0, 2, 18, 6, 11, 13, 1, 17, 16, 10, 9] -> [3, 5, 14, 8, 4, 7, 15, 0, 12, 19, 2, 6, 18, 11, 1, 13, 9, 10, 16, 17]

Оцінка балів

Це , тому виграє найкоротший код у байтах.


4
Що є головним у цьому методі сортування?
mbomb007

1
@ mbomb007 Я не дуже добре розумію нотацію big-o, але думаю, що одна ітерація - це O (n). Помножте це на найгірші n ітерації і ви отримаєте O (n ^ 2) (найгірший випадок; найкращим випадком буде O (n), я думаю, для однієї ітерації).
ETHproductions

1
Мені це звучить правильно, проте варто зазначити, що повернення масиву - не дуже ефективна операція, тому це повільноO(n^2)
DJMcMayhem

2
@WheatWizard для реверсування масиву не потребує місця для копії масиву, а лише місця для одного елемента. і є O(n). поміняйте місцями перший і останній елементи, потім поміняйте другими і другими останніми елементами і т.д.
Ясен

Поворот є O(n), але реверсування може бути вбудовано прямо в алгоритм (саме це і відповідає моя відповідь JS); оскільки кожна ітераційна петля над кожним елементом у масиві один раз, це одна ітерація O(n). (Я думаю ...)
ETHproductions

Відповіді:


19

JavaScript (ES6), 64 байти

f=([n,...a],z=[],q=[n,...z])=>a+a?n<a[0]?[...q,...f(a)]:f(a,q):q

Рекурсія FTW! Основний алгоритм, що використовується тут, - це відслідковувати поточний невибіжний пробіг у масиві, "повертаючи" його щоразу, коли буде знайдений висхідний елемент. Ми робимо це рекурсивно, постійно об'єднуючи результати, поки не закінчимось предметами. Створюючи кожен прогон у зворотному порядку ( [n,...z]замість [...z,n]), ми можемо уникнути тривалої .reverse()безціни.

Фрагмент тесту


Чи можете ви пояснити, як ваш масив розбирається на ваш перший параметр [n,...a]. Що таке n? Це лише перший елемент у вашому масиві?
Олівер

1
@obarakon Правильно. nє першим елементом у масиві та aрештою масиву. Більше інформації ви можете знайти тут .
ETHproductions

Дякую. Це було дуже корисно. Оскільки ваш перший параметр - це масив, чому вам потрібно включати ...a? Це просто так, щоб ви могли скористатися n? Ще одна річ, коли ви телефонуєте f(a,q), qвстановлюється параметр z?
Олівер

1
@obarakon Добре, f=([n])=>...захоплював би лише перший елемент, а f=([n,a])=>...захоплював би лише перший в nі другий в a. Ще один спосіб зробити те f=([n,...a])=>,,,, що буде f=a=>(n=a.unshift(),....
ETHproductions

1
А оскільки zдругий параметр функції, коли f(a,q)він викликається, fбачить його як z. Сподіваюся, це допомагає!
ETHproductions


11

Желе , 8 байт

Ṁ;<œṗ³UF

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

Пояснення:

Ṁ;         Prepend the list [a1, a2… an] with its maximum.
  <        Elementwise compare this with the original list:
           [max(a) < a1, a1 < a2, …, a(n-1) < an, an]
           The first element is always 0.
   œṗ³     Partition the original list (³) at the indices
           of the non-zero values in the working list.
           (The spurious `an` at the end of the left argument,
           resulting from comparing lists of different sizes,
           is ignored by this operation, thankfully.)
      U    Reverse each part.
       F   Flatten.

1
Я був на межі враження Save Edits, коли побачив вашу відповідь ... Молодці.
Денніс

@Dennis Heh, значить, ви додали Dyalog-додаток, але що з розділом APL2?
Адам

11

JavaScript (ES6), 70 байт

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

a=>a.map((n,i)=>a[x=[...o,...r=[n,...r]],i+1]>n&&(o=x,r=[]),r=o=[])&&x

Примітка: Ініціалізація і того rі іншого oоб'єкта r = o = []може виглядати як небезпечна ідея. Але це безпечно зробити тут, оскільки rодразу призначається власний екземпляр (містить перший елемент a) на першій ітерації з r = [n, ...r].

Тестові справи


2
Не хвилюйтесь, я люблю бачити різні підходи. І часто після гри в гольф стає коротше, ніж інше :-)
ETHproductions

8

MATL , 15 байт

lidO>vYsGhXSOZ)

Вхід - вектор стовпця з форматом [5; 2; 7; 6; 4; 1; 3](крапка з комою - роздільник рядків).

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

Візьмемо [5; 2; 7; 6; 4; 1; 3]приклад як приклад.

Пояснення

l     % Push 1
      % STACK: 1
i     % Push input
      % STACK: 1, [5; 2; 7; 6; 4; 1; 3]
d     % Consecutive differences
      % STACK: 1, [-3; 5; -1; -2; -3; 2]
O>    % Test if greater than 0, element-wise
      % STACK: 1, [0; 1; 0; 0; 0; 1]
v     % Concatenate vertically
      % STACK: [1; 0; 1; 0; 0; 0; 1]
Ys    % Cumulative sum
      % STACK: [1; 1; 2; 2; 2; 2; 3]
G     % Push input again
      % STACK: [1; 1; 2; 2; 2; 2; 3], [5; 2; 7; 6; 4; 1; 3]
h     % Concatenate horizontally
      % STACK: [1 5; 1 2; 2 7; 2 6; 2 4; 2 1; 3 3]
XS    % Sort rows in lexicographical order
      % STACK: [1 2; 1 5; 2 1; 2 4; 2 6; 2 7; 3 3]
OZ)   % Get last column. Implicitly display
      % STACK: [2; 5; 1; 4; 6; 7; 3]

Я переклав вашу відповідь на Octave, врятував мене 31 байт!
rahnema1

7

Математика, 30 27 байт

3 байти збережено завдяки @Martin Ender .

Join@@Sort/@Split[#,#>#2&]&

Анонімна функція. Бере список списку чисел як вхідний і повертає список чисел як вихідний.


Бий мене до цього! :)
Грег Мартін

5

Python 2, 100 байт

По-справжньому жахливий гольф, але я хотів опублікувати своє рішення (один не просто перевершив Денніса) ...

d=input();L=[];x=0;d+=-~d[-1],
for i in range(1,len(d)):
 if d[i]>d[i-1]:L+=d[x:i][::-1];x=i
print L

Тест на repl.it!

Вхід повинен бути наданий як буквальний список Python, такий як [5, 3, 4, 2, 6, 1].

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


Я думаю, що перший рядок може бути d,L,x=input(),[],0;d+=....
Даніель

@Dopapp точно такий же кількість байтів
FlipTack


4

Сітківка , 163 байти

Так, я знаю, наскільки це жахливо. Підтримують нулі і негативи були супер весело. Кількість байтів передбачає кодування ISO 8859-1.

\d+
$*
(?<=-1*)1
x
-

x,1
x¶1
\b(1+),(1+\1)\b
$1¶$2
,,1
,¶1
x,(¶|$)
x¶¶
(?<=\b\1x+(?=,(x+))),\b
¶
O%$#`.(?=(.*))
$.1
+`¶
,
\bx
-x
(\w+)
$.1
^,
0,
,$
,0
,,
,0,
^$
0

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

Пояснення:

\d+                         # Convert to unary
$*
(?<=-1*)1                   # Replace negatives with x's instead of 1's
x
-                           # Remove minus sign

x,1                         # Separate if negative before positive
x¶1
\b(1+),(1+\1)\b             # or greater positive follows a positive
$1¶$2
,,1                         # or positive follows a zero
,¶1
x,(¶|$)                     # or zero follows a negative
x¶¶
(?<=\b\1x+(?=,(x+))),\b     # or negative follows a negative of greater magnitude.
¶
O%$#`.(?=(.*))              # Swear at the input, then reverse each line
$.1
+`¶                         # Remove breaks, putting commas back
,
\bx                         # Put the minus signs back
-x
(\w+)                       # Replace unary with length of match (decimal)
$.1
^,                          # Do a bunch of replacements to resurrect lost zeros
0,
,$
,0
,,
,0,
^$
0

4

05AB1E , 19 18 16 14 байт

Збережено 2 байти, використовуючи сортувальний трюк Луїса Мендо

ü‹X¸ì.pO¹)ø{ø¤

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

Пояснення

Приклад введення [5, 2, 7, 6, 4, 1, 3]

ü‹               # pair-wise less-than
                 # STACK: [0, 1, 0, 0, 0, 1]
  X¸ì            # prepend a 1
                 # STACK: [1, 0, 1, 0, 0, 0, 1]
     .p          # prefixes
       O         # sum
                 # STACK: [1, 1, 2, 2, 2, 2, 3]
        ¹        # push input
                 # STACK: [1, 1, 2, 2, 2, 2, 3], [5, 2, 7, 6, 4, 1, 3]
         )       # wrap stack in list
                 # STACK: [[1, 1, 2, 2, 2, 2, 3], [5, 2, 7, 6, 4, 1, 3]]
          ø      # zip
                 # STACK: [[1, 5], [1, 2], [2, 7], [2, 6], [2, 4], [2, 1], [3, 3]]
           {     # sort
                 # STACK: [[1, 2], [1, 5], [2, 1], [2, 4], [2, 6], [2, 7], [3, 3]]
            ø    # zip
                 # STACK: [[1, 1, 2, 2, 2, 2, 3], [2, 5, 1, 4, 6, 7, 3]]
             ¤   # tail
                 # OUTPUT: [2, 5, 1, 4, 6, 7, 3]

Попереднє 16-байтне рішення

Dü‹X¸ì.pO.¡€g£í˜

Ці рядкові перерви це чудово пояснили ... :-P
Стюі Гріффін

@StewieGriffin: Так, я змінив код і опублікував, перш ніж переписав пояснення: P
Emigna

4

JavaScript (ECMA 6), 121 128 125 119 108 байт

f=a=>{p=a[0],c=[],b=[];for(e of a){e>p&&b.push(c.reverse(c=[]));c.push(p=e)}return[].concat.call([],...b,c)}

Лямбда - вираз приймає один Arrayпараметр, a.

Завдяки @ETHproductions за те, що допомогли мені побачити свою першу помилку.


Приємно! Я думаю, ви можете зробити, return(b+","+c).split`,` щоб зберегти кілька байт в кінці.
ETHproductions

1
А ще краще, ви можете використовувати c.unshiftзамість того, c.pushщоб зняти необхідність повернення назад c. Після цього я отримав 94 байти .
ETHproductions

3

Рубін, 60 55 байт

s=->x{x.slice_when{|p,q|p<q}.map{|z|z.reverse}.flatten} 

Досить багато того, про що вимагали виклики. Я визначив лямбда s, яка бере масив x, і розділити (нарізати) її на більш дрібні шматочки, де наступний елемент буде більшим, ніж. Це повертає нумератор, на який ми можемо викликати карту і відміняти порядок фігур, перш ніж нарешті об'єднати це все з площиною, яка об'єднує елементи у визначеному порядку в один масив.

Тести

p s[[1]]===[1]
p s[[1, 1]]===[1, 1]
p s[[1, 2]]===[1, 2]
p s[[2, 1]]===[1, 2]
p s[[2, 3, 1]]===[2, 1, 3]
p s[[2, 1, 3]]===[1, 2, 3]
p s[[2, 1, 2]]===[1, 2, 2]
p s[[2, 1, 1]]===[1, 1, 2]
p s[[3, 1, 1, 2]]===[1, 1, 3, 2]
p s[[3, 2, 1, 2]]===[1, 2, 3, 2]
p s[[3, 1, 2, 2]]===[1, 3, 2, 2]
p s[[1, 3, 2, 2]]===[1, 2, 2, 3]
p s[[1, 0, 5, -234]]===[0, 1, -234, 5]
p s[[1, 0, 1, 0, 1]]===[0, 1, 0, 1, 1]
p s[[1, 2, 3, 4, 5]]===[1, 2, 3, 4, 5]
p s[[5, 4, 3, 2, 1]]===[1, 2, 3, 4, 5]
p s[[2, 1, 5, 4, 3]]===[1, 2, 3, 4, 5]
p s[[2, 3, 1, 5, 4]]===[2, 1, 3, 4, 5]
p s[[5, 1, 4, 2, 3]]===[1, 5, 2, 4, 3]
p s[[5, 2, 7, 6, 4, 1, 3]]===[2, 5, 1, 4, 6, 7, 3]
p s[[-5, -2, -7, -6, -4, -1, -3]]===[-5, -7, -2, -6, -4, -3, -1]
p s[[14, 5, 3, 8, 15, 7, 4, 19, 12, 0, 2, 18, 6, 11, 13, 1, 17, 16, 10, 9]]===[3, 5, 14, 8, 4, 7, 15, 0, 12, 19, 2, 6, 18, 11, 1, 13, 9, 10, 16, 17]

1
Ласкаво просимо, хороший <s> перший </ s> другий відповідь, перевірити це: codegolf.stackexchange.com/questions/363 / ...
GB

Дуже дякую. Перетворив це в лямбда, як було запропоновано у наданому посиланням, і таким чином зберег 5 байт.
манотехніка

2

Брахілог , 10 байт

~c:{>=r}ac

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

Пояснення

~c            Deconcatenate the Input
  :{>=r}a     Each resulting sublist must be non-increasing, and then reverse it
         c    Concatenate

Чи Брахілог c, коли працює заднім ходом, обов’язково спершу намагається розділити їх на меншу кількість списків?

@ ais523 так, це так.
Фаталізувати

1

Діалог APL , 7 15 байт

Потрібно ⎕ML←3, що для багатьох систем за замовчуванням. *

{∊⌽¨⍵⊂⍨1+⍵-⌊/⍵}

заручитися (згладити)

⌽¨ кожен перевернутий

⍵⊂⍨ аргумент розділений * шляхом вирізання, де кожен відповідний елемент більший, ніж його попередник

1+ один плюс

⍵- аргумент мінус

⌊/⍵ найменший елемент аргументу


Старе 7-байтне рішення не вдається з непозитивними цілими числами:

Потрібно ⎕ML←3, що для багатьох систем за замовчуванням. *

∊⌽¨⊆⍨⎕

зарахувати (згладити)

⌽¨ кожен перевернутий

⊂⍨ саморозподіл *


* Partition ( ) - це функція, яка скорочує правий аргумент, якщо відповідний лівий аргумент більший за попередній. (На жаль, він приймає лише негативні цілі числа, а нуль має особливе значення.) З версії 16 ця функціональність доступна у всіх системах (навіть у тих, де вони є ⎕ML≠3), використовуючи гліф .


1

Haskell, 49 байт

(a:b)%l|any(<a)l=l++b%[a]|1<2=b%(a:l)
_%l=l
(%[])

Приклад використання: (%[]) [5,2,7,6,4,1,3]-> [2,5,1,4,6,7,3].

Рекурсивний підхід. Функція %приймає список вхідного сигналу як його перший параметр і акумулятор, lякий відслідковує поки що не зростаючий фрагмент (у зворотному порядку). Базовий випадок досягається, коли вхідний список порожній і тоді результат - акумулятор. Якщо вхідний список не порожній і перший елемент aне вписується у поточний фрагмент ( any(<a)l), поверніть акумулятор та додайте рекурсивний виклик у решту списку та aяк новий акумулятор ( l++b%[a]). В іншому випадку зробіть рекурсивний дзвінок у решті списку і aприкинувшись до акумулятора tha ( b%(a:l)). Основна функція (%[])дзвінки %з порожнім акумулятором.



1

R, 64 байти

cat(unlist(lapply(split(x<-scan(),cumsum(c(F,diff(x)>0))),rev)))

Читає дані від stdin. Ми розділили вхід на список векторів, за допомогою split()яких потрібна факторна змінна, яка групує вхід. Коефіцієнт створюється шляхом взяття сукупної суми логічного вектора, для якого різниця позитивна.

Розглянемо вектор:

x=c(5, 2, 7, 6, 4, 1, 3)

Тепер, якщо взяти різницю та попередньо Fзапустити біг, y=c(F,diff(x)>0)вийде такий логічний вектор:

[1] FALSE FALSE  TRUE FALSE FALSE FALSE  TRUE

Беручи сукупну суму, cumsum(y)утворюється вектор, де кожна група представлена ​​унікальним фактором, за яким ми можемо комбінувати splitфункцію:

[1] 0 0 1 1 1 1 2

60 байт , використовуючи diffinvзамість cumsum.
Джузеппе

1

Октава, 75 44 байти

На основі відповіді MATL @LuisMendo

@(a)sortrows([cumsum([1;diff(a)>0]),a])(:,2)

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

Попередня відповідь

@(a)[fliplr(mat2cell(f=fliplr(a),1,diff(find([1,diff(f)<0,numel(a)])))){:}]

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

повернути масив

f=fliplr(a)

прийняти першу різницю f

d = diff(f);

знайти положення, де наступний елемент менший, ніж попередній

p=find([1,diff(f)<0,numel(a)])

Перша різниця позицій повертає довжину кожного підсистеми

len=diff(p)

використовувати довжину кожного підмасиву в, mat2cellщоб розділити масив на вкладений список масивів

nest = mat2cell(f,1,len);

повернути вкладений список

rev_nest = fliplr(nest) 

вирівняти вкладений список

[rev_nest{:}]


0

Perl 6 , 59 байт

{map |+«*.[0].reverse,m/:s([(\-?\d+)<?{[>=] $0}>] +)+/[0]}

Розчин на основі Regex
Тому що це Спарта Перл !!

  • m/ /: Струфікуйте вхідний масив і порівняйте його з регулярним виразом.
  • (\-? \d+): Зіставити число і захопити його як $0.
  • <?{ [>=] $0 }>: Затвердження нульової ширини, яке відповідає лише тому, що всі $0захоплені до цього моменту в поточному під-матчі знаходяться в порядку зростання.
  • ([ ] +)+: Повторіть останні два кроки якомога частіше, інакше почніть новий підрозділ.
  • map , [0]: Повторне повторення під-матчів.
  • |+«*.[0].reverse: Для кожного візьміть список зіставлених значень $0, переверніть його, примусьте значення до чисел ( ) та перенесіть їх у зовнішній список ( |).

Perl 6 , 63 байти

sub f(\a){flat $_,f a[+$_..*]with first {[<=] $_},:end,[\R,] a}

Рекурсивне рішення для обробки списку.
Більш трудомісткий, ніж я сподівався.
Незважаючи на те, що в мові є багато зручних вбудованих програм, схоже, немає жодного для розділення списку (наприклад, як у Ruby's slice_whenабо Haskell takeWhile).


0

Складений , неконкурентоспроможний, 34 байти

Досі постійно розвиває цю мову.

{e.b:e b last<}chunkby$revmap flat

Аргумент лежить на TOS. Спробуйте тут!

chunkbyприймає функцію і збирає масиви суміжних даних, які задовольняють функцію. Функція тоді:

{e.b:e b last<}
{e.b:         }  function with arguments [e, <unused>, b]--the element, <the index>, and the
                 chunk being built
     e       <   check if e is less than
       b last    the last element of b

Це дає суворо зменшується масив.

$revmap в основному [rev]map і обертає кожен елемент.

flat нарешті згладжує масив.


Деяке задоволення від фактичного сортування масиву:

[{e.b:e b last<}chunkby$revmap flat] @:sortstep
[$sortstep periodloop] @:sort

10:> @arr
arr out
arr shuf @arr
arr out
arr sort out

Це результати (наприклад):

(0 1 2 3 4 5 6 7 8 9)
(4 5 1 0 6 7 2 8 9 3)
(0 1 2 3 4 5 6 7 8 9)

0

Пітон, 151 139 байт

Збережено 12 байт завдяки @ Flp.Tkc!

Ніде поблизу @ Flp.Tkc, не кажучи вже про ...

def s(l):
 r=[];i=j=0
 while j<len(l)-1:
  if l[j+1]>l[j]:r+=l[i:j+1][::-1],;i=j+1
  j+=1
 r+=l[i:j+1][::-1],;return[i for s in r for i in s]

Замість того, щоб додати, використовуйте += data,коду, що відкладається, неявно будує кортеж, який потім з'єднується зі списком, додаючи дані як останній елемент у списку. У цьому контексті зробітьr+=l[i:j+1][::-1],
FlipTack


0

Пітон 3, 191 байт

a=[int(i)for i in input().split()]
while a!=sorted(a):
 b=[[]]
 for i,j in enumerate(a):
  if a[i-1]<j:b+=[[j]]
  else:b[-1]+=[j]
 a=[]
 for l in[k[::-1]for k in b]:a+=[k for k in l]
print(a)

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


0

Clojure, 105 байт

#(filter number?(mapcat reverse(partition-by not(mapcat(fn[[a b]][a(< b a)])(partition 2 1(conj % 1))))))

Розбиття на пари на послідовних числах, ставлячи trueабо falseміж ними, перегородки на notна trueта числа стають falseі false true, обертають розділи та зберігають числові значення.

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