Plus petit nombre de sous-séquences monotones contiguës

23

Description du défi

Une sous -séquence monotone est une séquence de nombres [a1, a2, ..., an]telle que

a1 <= a2 <= ... <= anou a1 >= a2 >= ... >= an. [1, 3, 3, 7, 9, 13, 13, 100]est une sous-séquence monotone (non décroissante), ainsi que [9, 4, 4, 3, 0, -10, -12](celle-ci n'est pas croissante), mais [1, 3, 6, 9, 8]ne l'est pas. Étant donné une liste d'entiers (dans n'importe quel format raisonnable), affichez le plus petit nombre de Nsorte que la séquence de ces entiers puisse être divisée en Nséquences monotones.

Exemples

[1, 3, 7, 5, 4, 2] -> [[1, 3, 7], [5, 4, 2]] -> 2
[1, 2, 3, 4, 5, 6] -> [1, 2, 3, 4, 5, 6]     -> 1
[3, 1, 5, 5, 6]    -> [[3, 1], [5, 5, 6]]    -> 2
[4, 6, 8, 9, 1, 6] -> [[4, 6, 8, 9], [1, 6]] -> 2
[3, 3, 3, 3]       -> [[3, 3, 3, 3]]         -> 1
[7]                -> [[7]]                  -> 1
[]                 -> []                     -> anything (you don't actually have to handle an empty list case)
[1, 3, 2, -1, 6, 9, 10, 2, 1, -12] -> [[1, 3], [2, -1], [6, 9, 10], [2, 1, -12]] -> 4
shooqie
la source
Pour clarifier, les sous-séquences doivent être contiguës, non?
Zgarb
@Zgarb Oui, ils le font.
shooqie
3
Je recommanderais d'ajouter un cas de test où les séquences ne vont pas toujours dans le sens inverse: [4,4,8,8,1,4,5] -> 2
Nathan Merrill
@NathanMerrill: Bon point, a ajouté un.
shooqie
Lorsque vous écrivez cela pour une chaîne vide, le résultat est 0 / undefined, il semble que ce devrait être 0 ou la représentation de undefineddans notre langue, mais d'après votre commentaire sur la réponse Jelly de Jonathan Allan, cela ressemble à des undefinedmoyens anything... Lequel est-ce? ? Dans le deuxième cas, je suggère d'écrire anythingau lieu deundefined
Dada

Réponses:

6

Brachylog , 12 octets

~c:{<=|>=}al

Essayez-le en ligne!

Cela revient false.pour la liste vide [].

Explication

(?)~c                 Take a list of sublists which when concatenated result in the Input
     :{<=|>=}a        Each sublist must be either increasing or decreasing
              l(.)    Output is the length of that list

Cela renverra le plus petit car ~cgénérera des points de choix du plus petit nombre de sous-listes au plus grand.

Fatalize
la source
Quel est l'argument "Z" dans le lien TIO? (Il semble faire partie du programme comme le ferait un argument de ligne de commande).
Jonathan Allan
@JonathanAllan Cet argument est la sortie. Idéalement, si nous pouvions personnaliser l'interface de TIO, il y aurait l'entrée et la sortie et aucun argument. L'argument est Zparce que Zc'est un nom de variable; nous disons donc "appelez ce programme avec la sortie comme variable". Vous pouvez passer Zà n'importe quelle autre lettre majuscule ; c'est juste un nom de variable. La raison pour laquelle cet argument existe est de permettre la possibilité de définir réellement la sortie sur quelque chose, au lieu d'une variable.
Fatalize
(Par exemple, si vous définissez la sortie sur 4dans cet exemple, il vous dira si c'est correct ou non )
Fatalize
1
@JonathanAllan Tout langage comme Prolog est comme ceci: les prédicats ne peuvent que réussir ou échouer et ne retournent aucune valeur. Donc, pour obtenir une sortie, il faut avoir un argument variable au prédicat qui sera unifié au résultat.
Fatalize
1
@JonathanAllan Il finira par échouer 3car il ne trouvera aucune liste de sous-listes où toutes sont monotones et de longueur 3. Cela prend juste beaucoup de temps car il va essayer toutes les listes possibles de sous-listes, même celles qui sont en fait plus longues que 3 éléments car la longueur est vérifiée après avoir trouvé la liste. Car 5cela dit truecar il y a en effet au moins une liste de longueur 5avec des sous-listes monotones qui fonctionne. Donc, ce programme renvoie la plus petite longueur lorsque la sortie est une variable et s'il existe une liste de cette longueur qui fonctionne si la sortie est un entier.
Fatalize
4

Perl, 65 octets

62 octets de code + 3 octets pour l' -nindicateur.

monot_seq.pl:

#!perl -n
s/\S+ /($_<=>$&)*($&<=>$')-$g>=0?$g=1:$.++;$g--;$_=$&/ge,$_=$.

Donnez l'entrée sans nouvelle ligne finale, avec les nombres séparés par des espaces:

$ echo -n "1 3 2 -1 6 9 10 2 1 -12" | perl -M5.010 monot_seq.pl
4

-5 octets grâce à @Gabriel Benamy.

Dada
la source
Epargnez 5 octets en tournant ($&<=>$1)*($1<=>$2)||$1==$2en($&<=>$1)*($1<=>$2)>=0
Gabriel Benamy
@GabrielBenamy En effet, merci.
Dada
2

Mathematica, 111 octets

d=#[[2]]-#[[1]]&;r=Rest;f@{n_}:=1;f@k__:=If[d@k==0,f@r@k,g[k Sign@d@k]];g@{n_}:=1;g@k__:=If[d@k>0,g@r@k,1+f@r@k]

Fonction nommée fprenant une liste non vide de nombres (entiers ou même réels). Fonctionne d'avant en arrière, en rejetant le premier élément à plusieurs reprises et en gardant une trace du nombre de sous-séquences nécessaires. Plus verbeux:

d = #[[2]] - #[[1]] &;         function: difference of the first two elements
r = Rest;                      function: a list with its first element dropped
f@{n_} := 1;                   f of a length-1 list equals 1
f@k__ := If[d@k == 0, f@r@k,   if the first two elements are equal, drop one
                                 element and call f again ...
            g[k Sign@d@k]];  ... otherwise call the helper function g on the
                                 list, multiplying by -1 if necessary to ensure
                                 that the list starts with an increase
g@{n_} := 1;                   g of a length-1 list equals 1
g@k__ := If[d@k > 0, g@r@k,    if the list starts with an increase, drop one
                                 element and call g again ...
            1 + f@r@k];        ... otherwise drop one element, call f on the
                                 resulting list, and add 1
Greg Martin
la source
d=#2-#&@@#&;également, la définition de l'opérateur unaire fou gde celui-ci ±permettra probablement d'économiser quelques octets.
Martin Ender
2

Gelée , 19 octets

IṠḟ0E
ŒṖÇ€€0e$Ðḟḅ1Ṃ

TryItOnline! ou exécutez tous les tests (les résultats de la liste vide dans1)

Comment?

IṠḟ0E - Link 1, test for monotonicity: a sublist
I     - incremental differences
 Ṡ    - sign {fall:-1; same:0; rise:1}
  ḟ0  - filter out the zeros
    E - all equal?

ŒṖÇ€€0e$Ðḟḅ1Ṃ - Main link
ŒṖ            - all partitions of the input list
  Ç€€         - call last link (1) as a monad for €ach for €ach
        Ðḟ    - filter out results:
       $      -    last two links as a monad
     0e       -        contains zero?
          ḅ1  - convert from unary (vectorises)
            Ṃ - minimum

(Je ne suis pas convaincu que ce soit la méthode la plus appropriée pour minimiser le nombre d'octets)

Jonathan Allan
la source
@shooqie - Pouvons-nous retourner n'importe quelle valeur pour la liste vide étant donné le commentaire "non défini"? Cela revient 1(ce que je pense en fait plus de sens que 0).
Jonathan Allan
1
Je veux dire, c'est ce que cela undefinedsignifie - le résultat n'est pas pertinent.
shooqie
2

Perl, 98 97 96 79 octets

($a,$b)=($a<=>$b)*($b<=>$c)<0?($c,shift,$d++):($b,$c)while$c=shift;say$d+1 if$a

L'entrée est fournie sous la forme d'une liste de nombres, séparés par des espaces, fournis lors de l'exécution, par exemple

perl -M5.010 monotonic.pl 1 3 2 -1 6 9 10 2 1 -12
4

(le 4 est la sortie)

Lisible:

($a,$b)=($a<=>$b)*($b<=>$c)<0
    ?($c,shift,$d++)
    :($b,$c)
  while$c=shift;
say$d+1
  if$a

L'opérateur de vaisseau spatial <=>renvoie -1 si LHS <RHS, 0 si LHS = RHS et +1 si LHS> RHS. Lors de la comparaison de trois éléments séquentiels $a,$b,$cpour déterminer s'ils sont monotones, il suffit de déterminer que ce n'est pas le cas que l'un exactement $a<=>$b, $b<=>$cest 1 et l'autre est -1 - ce qui ne se produit que lorsque leur produit est -1. Si soit $a==$bou $b==$c, alors la séquence est monotone et le produit est 0. Si $a < $b < $c, alors les deux résultent en -1, et -1 * -1 = 1. Si $a > $b > $c, alors ils donnent tous les deux en 1, et 1 * 1 = 1. Dans les deux cas, la séquence est monotone et nous souhaitons continuer.

Si le produit est inférieur à 0, nous savons que la séquence n'est pas monotone, et nous rejetons les valeurs que $a,$bnous détenons actuellement et incrémentons notre compteur de sous-séquences. Sinon, on avance d'un chiffre.

Ne renvoie rien si l'entrée est vide, sinon renvoie le plus petit nombre de sous-séquences monotones contiguës

Gabriel Benamy
la source
Vous n'avez pas besoin d'un espace entre 1et if(ou peut-être que vous le faites sur les anciennes perles, mais sur les récentes, vous n'en avez pas). Vous pouvez également (probablement) remplacer shiftpar pop. Cependant, il existe certains cas de test sur lesquels votre code ne fonctionne pas: 6 3 6 3(vous imprimez 3 au lieu de 2), 4 3 2 1(vous imprimez 2 au lieu de 1). Utiliser popau lieu de shiftrésoudre ceux-ci mais en créer de nouveaux ( 1 2 3 4imprime 3 au lieu de 1) ...
Dada
1

C # 6, 297 209 octets

using System.Linq;int G(int[] a)=>a.Any()?a.SkipWhile((x,i)=>i<1||x>=a[i-1]).Count()<a.SkipWhile((x,i)=>i<1||x<=a[i-1]).Count()?G(a.Select(x=>-x).ToArray()):G(a.SkipWhile((x,i)=>i<1||x<=a[i-1]).ToArray())+1:0;

Non golfé avec des explications

int G(int[] a)=>
    a.Any()
        ?a.SkipWhile((x,i)=>i<1||x>=a[i-1]).Count()<a.SkipWhile((x,i)=>i<1||x<=a[i-1]).Count()   // If a begins by decreasing (including whole a decreasing)...
            ?G(a.Select(x=>-x).ToArray())   // ... Then flip sign to make a begins by increasing
            :G(a.SkipWhile((x,i)=>i<1||x<=a[i-1]).ToArray())+1   // ... Else skip the increasing part, recursively find the remaining part number, then add 1
        :0;   // Return 0 if a is empty
Link Ng
la source
1

JavaScript (ES6), 69 octets

f=(d,c,b,...a)=>1/b?(d>c)*(b>c)+(d<c)*(b<c)?1+f(b,...a):f(d,b,...a):1

Prend l'entrée comme plusieurs paramètres. Fonctionne en comparant récursivement les trois premiers éléments pour voir s'ils sont monotones, si c'est le cas, supprime l'élément du milieu car il est inutile, sinon, supprime les deux premiers éléments et commence une nouvelle séquence.

Neil
la source
0

Clojure, 97 octets

#((reduce(fn[[C i]s](let[S(conj C s)](if(or(apply <= S)(apply >= S))[S i][[s](inc i)])))[[]1]%)1)

reducegarde la trace de la sous-séquence actuelle et calcule le nombre de fois <=et les >=conditions échouent. Le dernier 1prend le 2e élément du résultat (étant le compteur i).

NikoNyrh
la source