Разберите массив


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). поменяйте местами первый и последний элементы, затем поменяйте местами второй и второй последние элементы и т. д., когда вы доберетесь до средней остановки.
Jasen

Реверс есть 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, когда увидел твой ответ ... Молодец.
Деннис

@ Денис Хех, значит, вы добавили 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]

Я перевёл твой ответ на октаву, сэкономил мне 31 байт!
rahnema1

7

Mathematica, 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и разделяет его (разбивает) на более мелкие части, где следующий элемент будет больше, чем. Это возвращает перечислитель, который мы можем вызвать map и обратить порядок частей, прежде чем, наконец, свести все это вместе с flatten, который объединяет элементы в определенном порядке в один массив.

тесты

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 байт.
Manonthemat

2

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

~c:{>=r}ac

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

объяснение

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

Обязательно ли Brachylog c, при запуске в обратном порядке, сначала разбивается на меньшее количество списков?

@ ais523 да, это так.
Fatalize

1

Дьялог АПЛ , 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не помещается в текущий chunk ( any(<a)l), верните аккумулятор и добавьте рекурсивный вызов к остальной части списка и aв качестве нового аккумулятора ( l++b%[a]). Иначе, сделайте рекурсивный вызов для остальной части списка и aдобавьте его в аккумулятор ( b%(a:l)). Основная функция (%[])вызывает %с пустым аккумулятором.



1

R, 64 байта

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

Читает ввод из стандартного ввода. Мы разбиваем входные данные на список векторов, для 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]}

Решение на основе регулярных выражений.
Потому что это Спарта Перл !!

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

Perl 6 , 63 байта

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

Решение для обработки рекурсивных списков.
Более трудоемкий, чем я надеялся.
Несмотря на то, что в языке есть много удобных встроенных функций, похоже, что для разбиения списка их нет (например, в Ruby 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

Python, 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

Python 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.